capybara 3.16.1 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +321 -0
  4. data/README.md +51 -60
  5. data/lib/capybara.rb +71 -114
  6. data/lib/capybara/config.rb +8 -5
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/node.rb +15 -3
  9. data/lib/capybara/dsl.rb +10 -2
  10. data/lib/capybara/helpers.rb +5 -3
  11. data/lib/capybara/minitest.rb +242 -141
  12. data/lib/capybara/minitest/spec.rb +159 -90
  13. data/lib/capybara/node/actions.rb +85 -74
  14. data/lib/capybara/node/base.rb +4 -4
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +216 -117
  18. data/lib/capybara/node/finders.rb +65 -65
  19. data/lib/capybara/node/matchers.rb +228 -126
  20. data/lib/capybara/node/simple.rb +9 -4
  21. data/lib/capybara/queries/ancestor_query.rb +5 -7
  22. data/lib/capybara/queries/base_query.rb +2 -1
  23. data/lib/capybara/queries/current_path_query.rb +1 -1
  24. data/lib/capybara/queries/selector_query.rb +296 -30
  25. data/lib/capybara/queries/sibling_query.rb +5 -4
  26. data/lib/capybara/queries/style_query.rb +2 -2
  27. data/lib/capybara/queries/text_query.rb +13 -1
  28. data/lib/capybara/queries/title_query.rb +1 -1
  29. data/lib/capybara/rack_test/browser.rb +7 -2
  30. data/lib/capybara/rack_test/driver.rb +1 -1
  31. data/lib/capybara/rack_test/form.rb +1 -1
  32. data/lib/capybara/rack_test/node.rb +43 -7
  33. data/lib/capybara/registration_container.rb +44 -0
  34. data/lib/capybara/registrations/drivers.rb +36 -0
  35. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  36. data/lib/capybara/registrations/servers.rb +44 -0
  37. data/lib/capybara/result.rb +36 -8
  38. data/lib/capybara/rspec/matcher_proxies.rb +6 -4
  39. data/lib/capybara/rspec/matchers.rb +100 -63
  40. data/lib/capybara/rspec/matchers/base.rb +23 -10
  41. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  42. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  43. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  44. data/lib/capybara/rspec/matchers/have_selector.rb +16 -8
  45. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  46. data/lib/capybara/rspec/matchers/have_text.rb +4 -4
  47. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  48. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  49. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  50. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  51. data/lib/capybara/selector.rb +219 -588
  52. data/lib/capybara/selector/builders/css_builder.rb +10 -6
  53. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  54. data/lib/capybara/selector/css.rb +4 -2
  55. data/lib/capybara/selector/definition.rb +277 -0
  56. data/lib/capybara/selector/definition/button.rb +52 -0
  57. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  58. data/lib/capybara/selector/definition/css.rb +10 -0
  59. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  60. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  61. data/lib/capybara/selector/definition/element.rb +27 -0
  62. data/lib/capybara/selector/definition/field.rb +40 -0
  63. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  64. data/lib/capybara/selector/definition/file_field.rb +13 -0
  65. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  66. data/lib/capybara/selector/definition/frame.rb +17 -0
  67. data/lib/capybara/selector/definition/id.rb +6 -0
  68. data/lib/capybara/selector/definition/label.rb +62 -0
  69. data/lib/capybara/selector/definition/link.rb +54 -0
  70. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  71. data/lib/capybara/selector/definition/option.rb +27 -0
  72. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  73. data/lib/capybara/selector/definition/select.rb +81 -0
  74. data/lib/capybara/selector/definition/table.rb +109 -0
  75. data/lib/capybara/selector/definition/table_row.rb +21 -0
  76. data/lib/capybara/selector/definition/xpath.rb +5 -0
  77. data/lib/capybara/selector/filter_set.rb +13 -9
  78. data/lib/capybara/selector/filters/base.rb +11 -2
  79. data/lib/capybara/selector/filters/locator_filter.rb +13 -3
  80. data/lib/capybara/selector/regexp_disassembler.rb +9 -2
  81. data/lib/capybara/selector/selector.rb +43 -448
  82. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  83. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  84. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  85. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  86. data/lib/capybara/selenium/driver.rb +125 -56
  87. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +73 -17
  88. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  89. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +41 -2
  90. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
  91. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +14 -5
  92. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  93. data/lib/capybara/selenium/extensions/find.rb +67 -45
  94. data/lib/capybara/selenium/extensions/html5_drag.rb +152 -36
  95. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  96. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  97. data/lib/capybara/selenium/node.rb +227 -56
  98. data/lib/capybara/selenium/nodes/chrome_node.rb +93 -8
  99. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  100. data/lib/capybara/selenium/nodes/firefox_node.rb +37 -59
  101. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  102. data/lib/capybara/selenium/nodes/safari_node.rb +27 -54
  103. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  104. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  105. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  106. data/lib/capybara/selenium/patches/logs.rb +45 -0
  107. data/lib/capybara/server.rb +19 -3
  108. data/lib/capybara/server/animation_disabler.rb +2 -2
  109. data/lib/capybara/server/checker.rb +6 -2
  110. data/lib/capybara/server/middleware.rb +23 -13
  111. data/lib/capybara/session.rb +124 -106
  112. data/lib/capybara/session/config.rb +12 -10
  113. data/lib/capybara/session/matchers.rb +6 -6
  114. data/lib/capybara/spec/public/offset.js +6 -0
  115. data/lib/capybara/spec/public/test.js +94 -5
  116. data/lib/capybara/spec/session/all_spec.rb +84 -6
  117. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  118. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  119. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  120. data/lib/capybara/spec/session/attach_file_spec.rb +14 -6
  121. data/lib/capybara/spec/session/check_spec.rb +10 -4
  122. data/lib/capybara/spec/session/choose_spec.rb +8 -2
  123. data/lib/capybara/spec/session/click_button_spec.rb +44 -1
  124. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  125. data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
  126. data/lib/capybara/spec/session/fill_in_spec.rb +37 -2
  127. data/lib/capybara/spec/session/find_spec.rb +60 -6
  128. data/lib/capybara/spec/session/first_spec.rb +1 -1
  129. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  130. data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
  131. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  132. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  133. data/lib/capybara/spec/session/has_css_spec.rb +35 -6
  134. data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
  135. data/lib/capybara/spec/session/has_field_spec.rb +34 -0
  136. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  137. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  138. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  139. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  140. data/lib/capybara/spec/session/has_text_spec.rb +47 -0
  141. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  142. data/lib/capybara/spec/session/node_spec.rb +574 -16
  143. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  144. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  145. data/lib/capybara/spec/session/scroll_spec.rb +1 -1
  146. data/lib/capybara/spec/session/select_spec.rb +5 -10
  147. data/lib/capybara/spec/session/selectors_spec.rb +24 -3
  148. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  149. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  150. data/lib/capybara/spec/session/window/window_spec.rb +10 -9
  151. data/lib/capybara/spec/spec_helper.rb +7 -2
  152. data/lib/capybara/spec/test_app.rb +26 -21
  153. data/lib/capybara/spec/views/animated.erb +49 -0
  154. data/lib/capybara/spec/views/form.erb +25 -4
  155. data/lib/capybara/spec/views/frame_child.erb +2 -1
  156. data/lib/capybara/spec/views/frame_one.erb +1 -0
  157. data/lib/capybara/spec/views/obscured.erb +9 -9
  158. data/lib/capybara/spec/views/offset.erb +32 -0
  159. data/lib/capybara/spec/views/react.erb +45 -0
  160. data/lib/capybara/spec/views/spatial.erb +31 -0
  161. data/lib/capybara/spec/views/with_animation.erb +29 -1
  162. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  163. data/lib/capybara/spec/views/with_html.erb +28 -2
  164. data/lib/capybara/spec/views/with_js.erb +2 -1
  165. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  166. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  167. data/lib/capybara/version.rb +1 -1
  168. data/lib/capybara/window.rb +10 -10
  169. data/spec/basic_node_spec.rb +6 -6
  170. data/spec/capybara_spec.rb +28 -28
  171. data/spec/dsl_spec.rb +16 -3
  172. data/spec/filter_set_spec.rb +5 -5
  173. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  174. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  175. data/spec/minitest_spec.rb +12 -2
  176. data/spec/minitest_spec_spec.rb +56 -45
  177. data/spec/rack_test_spec.rb +25 -12
  178. data/spec/regexp_dissassembler_spec.rb +53 -39
  179. data/spec/result_spec.rb +50 -54
  180. data/spec/rspec/features_spec.rb +1 -0
  181. data/spec/rspec/shared_spec_matchers.rb +78 -62
  182. data/spec/rspec_spec.rb +5 -5
  183. data/spec/sauce_spec_chrome.rb +1 -0
  184. data/spec/selector_spec.rb +26 -16
  185. data/spec/selenium_spec_chrome.rb +84 -5
  186. data/spec/selenium_spec_chrome_remote.rb +23 -8
  187. data/spec/selenium_spec_edge.rb +23 -8
  188. data/spec/selenium_spec_firefox.rb +16 -21
  189. data/spec/selenium_spec_firefox_remote.rb +4 -13
  190. data/spec/selenium_spec_ie.rb +23 -15
  191. data/spec/selenium_spec_safari.rb +17 -17
  192. data/spec/server_spec.rb +87 -42
  193. data/spec/session_spec.rb +11 -4
  194. data/spec/shared_selenium_node.rb +83 -0
  195. data/spec/shared_selenium_session.rb +62 -72
  196. data/spec/spec_helper.rb +43 -5
  197. metadata +114 -16
@@ -2,17 +2,17 @@
2
2
 
3
3
  module Capybara
4
4
  module RSpecMatcherProxies
5
- def all(*args, &block)
5
+ def all(*args, **kwargs, &block)
6
6
  if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
7
7
  ::RSpec::Matchers::BuiltIn::All.new(*args)
8
8
  else
9
- find_all(*args, &block)
9
+ find_all(*args, **kwargs, &block)
10
10
  end
11
11
  end
12
12
 
13
- def within(*args)
13
+ def within(*args, **kwargs, &block)
14
14
  if block_given?
15
- within_element(*args, &Proc.new)
15
+ within_element(*args, **kwargs, &block)
16
16
  else
17
17
  be_within(*args)
18
18
  end
@@ -21,6 +21,7 @@ module Capybara
21
21
  end
22
22
 
23
23
  if RUBY_ENGINE == 'jruby'
24
+ # :nocov:
24
25
  module Capybara::DSL
25
26
  class <<self
26
27
  remove_method :included
@@ -43,6 +44,7 @@ if RUBY_ENGINE == 'jruby'
43
44
  end
44
45
  end
45
46
  end
47
+ # :nocov:
46
48
  else
47
49
  module Capybara::DSLRSpecProxyInstaller
48
50
  module ClassMethods
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'capybara/rspec/matchers/have_selector'
4
+ require 'capybara/rspec/matchers/have_ancestor'
5
+ require 'capybara/rspec/matchers/have_sibling'
4
6
  require 'capybara/rspec/matchers/match_selector'
5
7
  require 'capybara/rspec/matchers/have_current_path'
6
8
  require 'capybara/rspec/matchers/match_style'
@@ -10,123 +12,142 @@ require 'capybara/rspec/matchers/become_closed'
10
12
 
11
13
  module Capybara
12
14
  module RSpecMatchers
13
- # RSpec matcher for whether the element(s) matching a given selector exist
14
- # See {Capybara::Node::Matcher#assert_selector}
15
- def have_selector(*args, &optional_filter_block)
16
- Matchers::HaveSelector.new(*args, &optional_filter_block)
15
+ # RSpec matcher for whether the element(s) matching a given selector exist.
16
+ #
17
+ # @see Capybara::Node::Matchers#assert_selector
18
+ def have_selector(*args, **kw_args, &optional_filter_block)
19
+ Matchers::HaveSelector.new(*args, **kw_args, &optional_filter_block)
17
20
  end
18
21
 
19
- # RSpec matcher for whether the element(s) matching a group of selectors exist
20
- # See {Capybara::Node::Matcher#assert_all_of_selectors}
21
- def have_all_of_selectors(*args, &optional_filter_block)
22
- Matchers::HaveAllSelectors.new(*args, &optional_filter_block)
22
+ # RSpec matcher for whether the element(s) matching a group of selectors exist.
23
+ #
24
+ # @see Capybara::Node::Matchers#assert_all_of_selectors
25
+ def have_all_of_selectors(*args, **kw_args, &optional_filter_block)
26
+ Matchers::HaveAllSelectors.new(*args, **kw_args, &optional_filter_block)
23
27
  end
24
28
 
25
- # RSpec matcher for whether no element(s) matching a group of selectors exist
26
- # See {Capybara::Node::Matcher#assert_none_of_selectors}
27
- def have_none_of_selectors(*args, &optional_filter_block)
28
- Matchers::HaveNoSelectors.new(*args, &optional_filter_block)
29
+ # RSpec matcher for whether no element(s) matching a group of selectors exist.
30
+ #
31
+ # @see Capybara::Node::Matchers#assert_none_of_selectors
32
+ def have_none_of_selectors(*args, **kw_args, &optional_filter_block)
33
+ Matchers::HaveNoSelectors.new(*args, **kw_args, &optional_filter_block)
29
34
  end
30
35
 
31
- # RSpec matcher for whether the element(s) matching any of a group of selectors exist
32
- # See {Capybara::Node::Matcher#assert_any_of_selectors}
33
- def have_any_of_selectors(*args, &optional_filter_block)
34
- Matchers::HaveAnySelectors.new(*args, &optional_filter_block)
36
+ # RSpec matcher for whether the element(s) matching any of a group of selectors exist.
37
+ #
38
+ # @see Capybara::Node::Matchers#assert_any_of_selectors
39
+ def have_any_of_selectors(*args, **kw_args, &optional_filter_block)
40
+ Matchers::HaveAnySelectors.new(*args, **kw_args, &optional_filter_block)
35
41
  end
36
42
 
37
- # RSpec matcher for whether the current element matches a given selector
38
- # See {Capybara::Node::Matchers#assert_matches_selector}
39
- def match_selector(*args, &optional_filter_block)
40
- Matchers::MatchSelector.new(*args, &optional_filter_block)
43
+ # RSpec matcher for whether the current element matches a given selector.
44
+ #
45
+ # @see Capybara::Node::Matchers#assert_matches_selector
46
+ def match_selector(*args, **kw_args, &optional_filter_block)
47
+ Matchers::MatchSelector.new(*args, **kw_args, &optional_filter_block)
41
48
  end
42
49
 
43
50
  %i[css xpath].each do |selector|
44
51
  define_method "have_#{selector}" do |expr, **options, &optional_filter_block|
45
- Matchers::HaveSelector.new(selector, expr, options, &optional_filter_block)
52
+ Matchers::HaveSelector.new(selector, expr, **options, &optional_filter_block)
46
53
  end
47
54
 
48
55
  define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
49
- Matchers::MatchSelector.new(selector, expr, options, &optional_filter_block)
56
+ Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
50
57
  end
51
58
  end
52
59
 
53
60
  # @!method have_xpath(xpath, **options, &optional_filter_block)
54
- # RSpec matcher for whether elements(s) matching a given xpath selector exist
55
- # See {Capybara::Node::Matchers#has_xpath?}
61
+ # RSpec matcher for whether elements(s) matching a given xpath selector exist.
62
+ #
63
+ # @see Capybara::Node::Matchers#has_xpath?
56
64
 
57
65
  # @!method have_css(css, **options, &optional_filter_block)
58
66
  # RSpec matcher for whether elements(s) matching a given css selector exist
59
- # See {Capybara::Node::Matchers#has_css?}
67
+ #
68
+ # @see Capybara::Node::Matchers#has_css?
60
69
 
61
70
  # @!method match_xpath(xpath, **options, &optional_filter_block)
62
- # RSpec matcher for whether the current element matches a given xpath selector
63
- # See {Capybara::Node::Matchers#matches_xpath?}
71
+ # RSpec matcher for whether the current element matches a given xpath selector.
72
+ #
73
+ # @see Capybara::Node::Matchers#matches_xpath?
64
74
 
65
75
  # @!method match_css(css, **options, &optional_filter_block)
66
- # RSpec matcher for whether the current element matches a given css selector
67
- # See {Capybara::Node::Matchers#matches_css?}
76
+ # RSpec matcher for whether the current element matches a given css selector.
77
+ #
78
+ # @see Capybara::Node::Matchers#matches_css?
68
79
 
69
80
  %i[link button field select table].each do |selector|
70
81
  define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block|
71
- Matchers::HaveSelector.new(selector, locator, options, &optional_filter_block)
82
+ Matchers::HaveSelector.new(selector, locator, **options, &optional_filter_block)
72
83
  end
73
84
  end
74
85
 
75
86
  # @!method have_link(locator = nil, **options, &optional_filter_block)
76
- # RSpec matcher for links
77
- # See {Capybara::Node::Matchers#has_link?}
87
+ # RSpec matcher for links.
88
+ #
89
+ # @see Capybara::Node::Matchers#has_link?
78
90
 
79
91
  # @!method have_button(locator = nil, **options, &optional_filter_block)
80
- # RSpec matcher for buttons
81
- # See {Capybara::Node::Matchers#has_button?}
92
+ # RSpec matcher for buttons.
93
+ #
94
+ # @see Capybara::Node::Matchers#has_button?
82
95
 
83
96
  # @!method have_field(locator = nil, **options, &optional_filter_block)
84
- # RSpec matcher for links
85
- # See {Capybara::Node::Matchers#has_field?}
97
+ # RSpec matcher for links.
98
+ #
99
+ # @see Capybara::Node::Matchers#has_field?
86
100
 
87
101
  # @!method have_select(locator = nil, **options, &optional_filter_block)
88
- # RSpec matcher for select elements
89
- # See {Capybara::Node::Matchers#has_select?}
102
+ # RSpec matcher for select elements.
103
+ #
104
+ # @see Capybara::Node::Matchers#has_select?
90
105
 
91
106
  # @!method have_table(locator = nil, **options, &optional_filter_block)
92
- # RSpec matcher for table elements
93
- # See {Capybara::Node::Matchers#has_table?}
107
+ # RSpec matcher for table elements.
108
+ #
109
+ # @see Capybara::Node::Matchers#has_table?
94
110
 
95
111
  %i[checked unchecked].each do |state|
96
112
  define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block|
97
- Matchers::HaveSelector.new(:field, locator, options.merge(state => true), &optional_filter_block)
113
+ Matchers::HaveSelector.new(:field, locator, **options.merge(state => true), &optional_filter_block)
98
114
  end
99
115
  end
100
116
 
101
117
  # @!method have_checked_field(locator = nil, **options, &optional_filter_block)
102
- # RSpec matcher for checked fields
103
- # See {Capybara::Node::Matchers#has_checked_field?}
118
+ # RSpec matcher for checked fields.
119
+ #
120
+ # @see Capybara::Node::Matchers#has_checked_field?
104
121
 
105
122
  # @!method have_unchecked_field(locator = nil, **options, &optional_filter_block)
106
- # RSpec matcher for unchecked fields
107
- # See {Capybara::Node::Matchers#has_unchecked_field?}
123
+ # RSpec matcher for unchecked fields.
124
+ #
125
+ # @see Capybara::Node::Matchers#has_unchecked_field?
108
126
 
109
- # RSpec matcher for text content
110
- # See {Capybara::Node::Matchers#assert_text}
111
- def have_text(*args)
112
- Matchers::HaveText.new(*args)
127
+ # RSpec matcher for text content.
128
+ #
129
+ # @see Capybara::Node::Matchers#assert_text
130
+ def have_text(text_or_type, *args, **options)
131
+ Matchers::HaveText.new(text_or_type, *args, **options)
113
132
  end
114
133
  alias_method :have_content, :have_text
115
134
 
116
135
  def have_title(title, **options)
117
- Matchers::HaveTitle.new(title, options)
136
+ Matchers::HaveTitle.new(title, **options)
118
137
  end
119
138
 
120
- # RSpec matcher for the current path
121
- # See {Capybara::SessionMatchers#assert_current_path}
139
+ # RSpec matcher for the current path.
140
+ #
141
+ # @see Capybara::SessionMatchers#assert_current_path
122
142
  def have_current_path(path, **options)
123
- Matchers::HaveCurrentPath.new(path, options)
143
+ Matchers::HaveCurrentPath.new(path, **options)
124
144
  end
125
145
 
126
- # RSpec matcher for element style
127
- # See {Capybara::Node::Matchers#matches_style?}
146
+ # RSpec matcher for element style.
147
+ #
148
+ # @see Capybara::Node::Matchers#matches_style?
128
149
  def match_style(styles, **options)
129
- Matchers::MatchStyle.new(styles, options)
150
+ Matchers::MatchStyle.new(styles, **options)
130
151
  end
131
152
 
132
153
  ##
@@ -138,25 +159,41 @@ module Capybara
138
159
  end
139
160
 
140
161
  %w[selector css xpath text title current_path link button
141
- field checked_field unchecked_field select table].each do |matcher_type|
142
- define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
143
- Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
162
+ field checked_field unchecked_field select table
163
+ sibling ancestor].each do |matcher_type|
164
+ define_method "have_no_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
165
+ Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, **kw_args, &optional_filter_block))
144
166
  end
145
167
  end
146
168
  alias_method :have_no_content, :have_no_text
147
169
 
148
170
  %w[selector css xpath].each do |matcher_type|
149
- define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
150
- Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
171
+ define_method "not_match_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
172
+ Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, **kw_args, &optional_filter_block))
151
173
  end
152
174
  end
153
175
 
176
+ # RSpec matcher for whether sibling element(s) matching a given selector exist.
177
+ #
178
+ # @see Capybara::Node::Matchers#assert_sibling
179
+ def have_sibling(*args, **kw_args, &optional_filter_block)
180
+ Matchers::HaveSibling.new(*args, **kw_args, &optional_filter_block)
181
+ end
182
+
183
+ # RSpec matcher for whether ancestor element(s) matching a given selector exist.
184
+ #
185
+ # @see Capybara::Node::Matchers#assert_ancestor
186
+ def have_ancestor(*args, **kw_args, &optional_filter_block)
187
+ Matchers::HaveAncestor.new(*args, **kw_args, &optional_filter_block)
188
+ end
189
+
154
190
  ##
155
191
  # Wait for window to become closed.
192
+ #
156
193
  # @example
157
194
  # expect(window).to become_closed(wait: 0.8)
158
- # @param options [Hash] optional param
159
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum wait time
195
+ #
196
+ # @option options [Numeric] :wait Maximum wait time. Defaults to {Capybara.configure default_max_wait_time}
160
197
  def become_closed(**options)
161
198
  Matchers::BecomeClosed.new(options)
162
199
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'capybara/rspec/matchers/compound'
4
+ require 'capybara/rspec/matchers/count_sugar'
5
+ require 'capybara/rspec/matchers/spatial_sugar'
4
6
 
5
7
  module Capybara
6
8
  module RSpecMatchers
@@ -10,22 +12,28 @@ module Capybara
10
12
 
11
13
  attr_reader :failure_message, :failure_message_when_negated
12
14
 
13
- def initialize(*args, &filter_block)
15
+ def initialize(*args, **kw_args, &filter_block)
14
16
  @args = args.dup
17
+ @kw_args = kw_args || {}
15
18
  @filter_block = filter_block
16
19
  end
17
20
 
18
21
  private
19
22
 
20
23
  def session_query_args
21
- if @args.last.is_a? Hash
22
- @args.last[:session_options] = session_options
23
- else
24
- @args.push(session_options: session_options)
25
- end
24
+ # if @args.last.is_a? Hash
25
+ # @args.last[:session_options] = session_options
26
+ # else
27
+ # @args.push(session_options: session_options)
28
+ # end
26
29
  @args
27
30
  end
28
31
 
32
+ def session_query_options
33
+ @kw_args[:session_options] = session_options
34
+ @kw_args
35
+ end
36
+
29
37
  def session_options
30
38
  @context_el ||= nil
31
39
  if @context_el.respond_to? :session_options
@@ -41,15 +49,15 @@ module Capybara
41
49
  class WrappedElementMatcher < Base
42
50
  def matches?(actual)
43
51
  element_matches?(wrap(actual))
44
- rescue Capybara::ExpectationNotMet => err
45
- @failure_message = err.message
52
+ rescue Capybara::ExpectationNotMet => e
53
+ @failure_message = e.message
46
54
  false
47
55
  end
48
56
 
49
57
  def does_not_match?(actual)
50
58
  element_does_not_match?(wrap(actual))
51
- rescue Capybara::ExpectationNotMet => err
52
- @failure_message_when_negated = err.message
59
+ rescue Capybara::ExpectationNotMet => e
60
+ @failure_message_when_negated = e.message
53
61
  false
54
62
  end
55
63
 
@@ -65,6 +73,11 @@ module Capybara
65
73
  end
66
74
  end
67
75
 
76
+ class CountableWrappedElementMatcher < WrappedElementMatcher
77
+ include ::Capybara::RSpecMatchers::CountSugar
78
+ include ::Capybara::RSpecMatchers::SpatialSugar
79
+ end
80
+
68
81
  class NegatedMatcher
69
82
  include ::Capybara::RSpecMatchers::Matchers::Compound if defined?(::Capybara::RSpecMatchers::Matchers::Compound)
70
83
 
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ module RSpecMatchers
5
+ module CountSugar
6
+ def once; exactly(1); end
7
+ def twice; exactly(2); end
8
+ def thrice; exactly(3); end
9
+
10
+ def exactly(number)
11
+ options[:count] = number
12
+ self
13
+ end
14
+
15
+ def at_most(number)
16
+ options[:maximum] = number
17
+ self
18
+ end
19
+
20
+ def at_least(number)
21
+ options[:minimum] = number
22
+ self
23
+ end
24
+
25
+ def times
26
+ self
27
+ end
28
+
29
+ private
30
+
31
+ def options
32
+ # (@args.last.is_a?(Hash) ? @args : @args.push({})).last
33
+ @kw_args
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'capybara/rspec/matchers/base'
4
+
5
+ module Capybara
6
+ module RSpecMatchers
7
+ module Matchers
8
+ class HaveAncestor < CountableWrappedElementMatcher
9
+ def element_matches?(el)
10
+ el.assert_ancestor(*@args, **session_query_options, &@filter_block)
11
+ end
12
+
13
+ def element_does_not_match?(el)
14
+ el.assert_no_ancestor(*@args, **session_query_options, &@filter_block)
15
+ end
16
+
17
+ def description
18
+ "have ancestor #{query.description}"
19
+ end
20
+
21
+ def query
22
+ # @query ||= Capybara::Queries::AncestorQuery.new(*session_query_args, &@filter_block)
23
+ @query ||= Capybara::Queries::AncestorQuery.new(*session_query_args, **session_query_options, &@filter_block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -7,11 +7,11 @@ module Capybara
7
7
  module Matchers
8
8
  class HaveCurrentPath < WrappedElementMatcher
9
9
  def element_matches?(el)
10
- el.assert_current_path(*@args)
10
+ el.assert_current_path(current_path, **@kw_args)
11
11
  end
12
12
 
13
13
  def element_does_not_match?(el)
14
- el.assert_no_current_path(*@args)
14
+ el.assert_no_current_path(current_path, **@kw_args)
15
15
  end
16
16
 
17
17
  def description