capybara 2.18.0 → 3.0.0.rc1

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +26 -1
  3. data/README.md +12 -12
  4. data/lib/capybara.rb +13 -25
  5. data/lib/capybara/config.rb +11 -57
  6. data/lib/capybara/cucumber.rb +2 -3
  7. data/lib/capybara/driver/base.rb +5 -16
  8. data/lib/capybara/driver/node.rb +5 -4
  9. data/lib/capybara/dsl.rb +1 -0
  10. data/lib/capybara/helpers.rb +16 -28
  11. data/lib/capybara/minitest.rb +139 -138
  12. data/lib/capybara/minitest/spec.rb +15 -14
  13. data/lib/capybara/node/actions.rb +59 -81
  14. data/lib/capybara/node/base.rb +11 -18
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +8 -8
  17. data/lib/capybara/node/element.rb +30 -40
  18. data/lib/capybara/node/finders.rb +62 -70
  19. data/lib/capybara/node/matchers.rb +48 -71
  20. data/lib/capybara/node/simple.rb +11 -17
  21. data/lib/capybara/queries/ancestor_query.rb +4 -6
  22. data/lib/capybara/queries/base_query.rb +18 -17
  23. data/lib/capybara/queries/current_path_query.rb +8 -24
  24. data/lib/capybara/queries/match_query.rb +3 -7
  25. data/lib/capybara/queries/selector_query.rb +92 -95
  26. data/lib/capybara/queries/sibling_query.rb +4 -4
  27. data/lib/capybara/queries/text_query.rb +37 -34
  28. data/lib/capybara/queries/title_query.rb +8 -11
  29. data/lib/capybara/rack_test/browser.rb +15 -18
  30. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  31. data/lib/capybara/rack_test/driver.rb +6 -10
  32. data/lib/capybara/rack_test/form.rb +50 -40
  33. data/lib/capybara/rack_test/node.rb +70 -56
  34. data/lib/capybara/rails.rb +2 -6
  35. data/lib/capybara/result.rb +22 -22
  36. data/lib/capybara/rspec.rb +5 -10
  37. data/lib/capybara/rspec/compound.rb +5 -10
  38. data/lib/capybara/rspec/features.rb +17 -48
  39. data/lib/capybara/rspec/matcher_proxies.rb +31 -15
  40. data/lib/capybara/rspec/matchers.rb +70 -60
  41. data/lib/capybara/selector.rb +129 -117
  42. data/lib/capybara/selector/css.rb +6 -11
  43. data/lib/capybara/selector/filter.rb +1 -17
  44. data/lib/capybara/selector/filter_set.rb +17 -14
  45. data/lib/capybara/selector/filters/base.rb +7 -6
  46. data/lib/capybara/selector/filters/expression_filter.rb +6 -23
  47. data/lib/capybara/selector/filters/node_filter.rb +2 -12
  48. data/lib/capybara/selector/selector.rb +27 -33
  49. data/lib/capybara/selenium/driver.rb +113 -127
  50. data/lib/capybara/selenium/node.rb +148 -113
  51. data/lib/capybara/server.rb +3 -2
  52. data/lib/capybara/session.rb +137 -223
  53. data/lib/capybara/session/config.rb +47 -67
  54. data/lib/capybara/session/matchers.rb +8 -7
  55. data/lib/capybara/spec/public/test.js +26 -4
  56. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
  57. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
  58. data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
  59. data/lib/capybara/spec/session/all_spec.rb +31 -18
  60. data/lib/capybara/spec/session/ancestor_spec.rb +2 -4
  61. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
  62. data/lib/capybara/spec/session/assert_current_path.rb +12 -11
  63. data/lib/capybara/spec/session/assert_selector.rb +1 -0
  64. data/lib/capybara/spec/session/assert_text.rb +18 -17
  65. data/lib/capybara/spec/session/assert_title.rb +1 -0
  66. data/lib/capybara/spec/session/attach_file_spec.rb +14 -13
  67. data/lib/capybara/spec/session/body_spec.rb +1 -0
  68. data/lib/capybara/spec/session/check_spec.rb +7 -6
  69. data/lib/capybara/spec/session/choose_spec.rb +5 -4
  70. data/lib/capybara/spec/session/click_button_spec.rb +20 -28
  71. data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
  72. data/lib/capybara/spec/session/click_link_spec.rb +8 -7
  73. data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
  74. data/lib/capybara/spec/session/current_url_spec.rb +7 -6
  75. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
  76. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
  77. data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
  78. data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
  79. data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
  80. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
  81. data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
  82. data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
  83. data/lib/capybara/spec/session/fill_in_spec.rb +6 -5
  84. data/lib/capybara/spec/session/find_button_spec.rb +4 -3
  85. data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
  86. data/lib/capybara/spec/session/find_field_spec.rb +8 -14
  87. data/lib/capybara/spec/session/find_link_spec.rb +6 -5
  88. data/lib/capybara/spec/session/find_spec.rb +37 -31
  89. data/lib/capybara/spec/session/first_spec.rb +60 -33
  90. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
  91. data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
  92. data/lib/capybara/spec/session/go_back_spec.rb +1 -0
  93. data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
  94. data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
  95. data/lib/capybara/spec/session/has_button_spec.rb +2 -1
  96. data/lib/capybara/spec/session/has_css_spec.rb +3 -2
  97. data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
  98. data/lib/capybara/spec/session/has_field_spec.rb +4 -3
  99. data/lib/capybara/spec/session/has_link_spec.rb +1 -0
  100. data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
  101. data/lib/capybara/spec/session/has_select_spec.rb +30 -29
  102. data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
  103. data/lib/capybara/spec/session/has_table_spec.rb +2 -1
  104. data/lib/capybara/spec/session/has_text_spec.rb +6 -5
  105. data/lib/capybara/spec/session/has_title_spec.rb +1 -0
  106. data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
  107. data/lib/capybara/spec/session/headers.rb +2 -1
  108. data/lib/capybara/spec/session/html_spec.rb +1 -0
  109. data/lib/capybara/spec/session/node_spec.rb +91 -56
  110. data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
  111. data/lib/capybara/spec/session/refresh_spec.rb +4 -2
  112. data/lib/capybara/spec/session/reset_session_spec.rb +1 -0
  113. data/lib/capybara/spec/session/response_code.rb +1 -0
  114. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  115. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
  116. data/lib/capybara/spec/session/save_page_spec.rb +1 -17
  117. data/lib/capybara/spec/session/save_screenshot_spec.rb +1 -1
  118. data/lib/capybara/spec/session/select_spec.rb +20 -20
  119. data/lib/capybara/spec/session/selectors_spec.rb +2 -2
  120. data/lib/capybara/spec/session/sibling_spec.rb +1 -1
  121. data/lib/capybara/spec/session/text_spec.rb +1 -0
  122. data/lib/capybara/spec/session/title_spec.rb +1 -1
  123. data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
  124. data/lib/capybara/spec/session/unselect_spec.rb +6 -5
  125. data/lib/capybara/spec/session/visit_spec.rb +9 -3
  126. data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
  127. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  128. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  129. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
  130. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
  131. data/lib/capybara/spec/session/window/window_spec.rb +12 -12
  132. data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
  133. data/lib/capybara/spec/session/window/within_window_spec.rb +13 -68
  134. data/lib/capybara/spec/session/within_spec.rb +1 -0
  135. data/lib/capybara/spec/spec_helper.rb +26 -18
  136. data/lib/capybara/spec/test_app.rb +8 -9
  137. data/lib/capybara/spec/views/form.erb +1 -0
  138. data/lib/capybara/spec/views/with_html.erb +3 -1
  139. data/lib/capybara/spec/views/within_frames.erb +4 -1
  140. data/lib/capybara/version.rb +2 -1
  141. data/lib/capybara/window.rb +6 -10
  142. data/spec/basic_node_spec.rb +1 -0
  143. data/spec/capybara_spec.rb +9 -32
  144. data/spec/dsl_spec.rb +5 -13
  145. data/spec/filter_set_spec.rb +5 -4
  146. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
  147. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
  148. data/spec/minitest_spec.rb +4 -3
  149. data/spec/minitest_spec_spec.rb +3 -2
  150. data/spec/per_session_config_spec.rb +9 -8
  151. data/spec/rack_test_spec.rb +21 -20
  152. data/spec/result_spec.rb +17 -16
  153. data/spec/rspec/features_spec.rb +17 -14
  154. data/spec/rspec/scenarios_spec.rb +5 -7
  155. data/spec/rspec/shared_spec_matchers.rb +96 -99
  156. data/spec/rspec/views_spec.rb +2 -1
  157. data/spec/rspec_matchers_spec.rb +19 -2
  158. data/spec/rspec_spec.rb +11 -15
  159. data/spec/selector_spec.rb +5 -6
  160. data/spec/selenium_spec_chrome.rb +7 -4
  161. data/spec/selenium_spec_marionette.rb +26 -12
  162. data/spec/server_spec.rb +33 -33
  163. data/spec/session_spec.rb +2 -1
  164. data/spec/shared_selenium_session.rb +27 -21
  165. data/spec/spec_helper.rb +2 -5
  166. metadata +66 -87
  167. data/lib/capybara/query.rb +0 -7
  168. data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,14 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'capybara/dsl'
3
4
 
4
5
  Capybara.app = Rack::Builder.new do
5
6
  map "/" do
6
- if Gem::Version.new(Rails.version) >= Gem::Version.new("3.0")
7
- run Rails.application
8
- else # Rails 2
9
- use Rails::Rack::Static
10
- run ActionController::Dispatcher.new
11
- end
7
+ run Rails.application
12
8
  end
13
9
  end.to_app
14
10
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'forwardable'
3
4
 
4
5
  module Capybara
5
-
6
6
  ##
7
7
  # A {Capybara::Result} represents a collection of {Capybara::Node::Element} on the page. It is possible to interact with this
8
8
  # collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation:
@@ -41,7 +41,7 @@ module Capybara
41
41
  loop do
42
42
  next_result = @results_enum.next
43
43
  @result_cache << next_result
44
- block.call(next_result)
44
+ yield next_result
45
45
  end
46
46
  self
47
47
  end
@@ -62,7 +62,7 @@ module Capybara
62
62
  !any?
63
63
  end
64
64
 
65
- def matches_count?
65
+ def compare_count
66
66
  # Only check filters for as many elements as necessary to determine result
67
67
  if @query.options[:count]
68
68
  count_opt = Integer(@query.options[:count])
@@ -70,7 +70,7 @@ module Capybara
70
70
  break if @result_cache.size > count_opt
71
71
  @result_cache << @results_enum.next
72
72
  end
73
- return @result_cache.size == count_opt
73
+ return @result_cache.size <=> count_opt
74
74
  end
75
75
 
76
76
  if @query.options[:minimum]
@@ -78,7 +78,7 @@ module Capybara
78
78
  begin
79
79
  @result_cache << @results_enum.next while @result_cache.size < min_opt
80
80
  rescue StopIteration
81
- return false
81
+ return -1
82
82
  end
83
83
  end
84
84
 
@@ -86,32 +86,38 @@ module Capybara
86
86
  max_opt = Integer(@query.options[:maximum])
87
87
  begin
88
88
  @result_cache << @results_enum.next while @result_cache.size <= max_opt
89
- return false
89
+ return 1
90
90
  rescue StopIteration
91
91
  end
92
92
  end
93
93
 
94
94
  if @query.options[:between]
95
- max = Integer(@query.options[:between].max)
95
+ min, max = @query.options[:between].minmax
96
96
  loop do
97
97
  break if @result_cache.size > max
98
98
  @result_cache << @results_enum.next
99
99
  end
100
- return false unless (@query.options[:between] === @result_cache.size)
100
+ return 0 if @query.options[:between].include?(@result_cache.size)
101
+ return -1 if @result_cache.size < min
102
+ return 1
101
103
  end
102
104
 
103
- return true
105
+ return 0
106
+ end
107
+
108
+ def matches_count?
109
+ compare_count.zero?
104
110
  end
105
111
 
106
112
  def failure_message
107
113
  message = @query.failure_message
108
- if count > 0
109
- message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
110
- else
114
+ if count.zero?
111
115
  message << " but there were no matches"
116
+ else
117
+ message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
112
118
  end
113
119
  unless rest.empty?
114
- elements = rest.map(&:text).map(&:inspect).join(", ")
120
+ elements = rest.map { |el| el.text rescue "<<ERROR>>" }.map(&:inspect).join(", ")
115
121
  message << ". Also found " << elements << ", which matched the selector but not all filters."
116
122
  end
117
123
  message
@@ -121,7 +127,7 @@ module Capybara
121
127
  failure_message.sub(/(to find)/, 'not \1')
122
128
  end
123
129
 
124
- private
130
+ private
125
131
 
126
132
  def full_results
127
133
  loop { @result_cache << @results_enum.next }
@@ -137,15 +143,9 @@ module Capybara
137
143
  # causes a concurrency issue with network requests here
138
144
  # https://github.com/jruby/jruby/issues/4212
139
145
  if RUBY_PLATFORM == 'java'
140
- @elements.select(&block).to_enum # non-lazy evaluation
141
- elsif @elements.respond_to? :lazy #Ruby 2.0+
142
- @elements.lazy.select(&block)
146
+ @elements.select(&block).to_enum # non-lazy evaluation
143
147
  else
144
- Enumerator.new do |yielder|
145
- @elements.each do |val|
146
- yielder.yield(val) if block.call(val)
147
- end
148
- end
148
+ @elements.lazy.select(&block)
149
149
  end
150
150
  end
151
151
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'rspec/core'
3
4
  require 'capybara/dsl'
4
5
  require 'capybara/rspec/matchers'
@@ -6,14 +7,9 @@ require 'capybara/rspec/features'
6
7
  require 'capybara/rspec/matcher_proxies'
7
8
 
8
9
  RSpec.configure do |config|
9
- config.include Capybara::DSL, :type => :feature
10
- config.include Capybara::RSpecMatchers, :type => :feature
11
- config.include Capybara::RSpecMatchers, :type => :view
12
-
13
- # A work-around to support accessing the current example that works in both
14
- # RSpec 2 and RSpec 3.
15
- fetch_current_example = RSpec.respond_to?(:current_example) ?
16
- proc { RSpec.current_example } : proc { |context| context.example }
10
+ config.include Capybara::DSL, type: :feature
11
+ config.include Capybara::RSpecMatchers, type: :feature
12
+ config.include Capybara::RSpecMatchers, type: :view
17
13
 
18
14
  # The before and after blocks must run instantaneously, because Capybara
19
15
  # might not actually be used in all examples where it's included.
@@ -26,10 +22,9 @@ RSpec.configure do |config|
26
22
 
27
23
  config.before do
28
24
  if self.class.include?(Capybara::DSL)
29
- example = fetch_current_example.call(self)
25
+ example = RSpec.current_example
30
26
  Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
31
27
  Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
32
28
  end
33
29
  end
34
30
  end
35
-
@@ -4,7 +4,7 @@ module Capybara
4
4
  include ::RSpec::Matchers::Composable
5
5
 
6
6
  def and(matcher)
7
- Capybara::RSpecMatchers::Compound::And.new(self,matcher)
7
+ Capybara::RSpecMatchers::Compound::And.new(self, matcher)
8
8
  end
9
9
 
10
10
  def and_then(matcher)
@@ -15,12 +15,9 @@ module Capybara
15
15
  Capybara::RSpecMatchers::Compound::Or.new(self, matcher)
16
16
  end
17
17
 
18
-
19
18
  class CapybaraEvaluator
20
- def initialize(actual, matcher_1, matcher_2)
21
- @actual = actual
22
- @matcher_1 = matcher_1
23
- @matcher_2 = matcher_2
19
+ def initialize(actual)
20
+ @actual = actual
24
21
  @match_results = Hash.new { |h, matcher| h[matcher] = matcher.matches?(@actual) }
25
22
  end
26
23
 
@@ -34,11 +31,10 @@ module Capybara
34
31
  end
35
32
 
36
33
  class And < ::RSpec::Matchers::BuiltIn::Compound::And
37
-
38
34
  private
39
35
 
40
36
  def match(_expected, actual)
41
- @evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
37
+ @evaluator = CapybaraEvaluator.new(actual)
42
38
  syncer = sync_element(actual)
43
39
  begin
44
40
  syncer.synchronize do
@@ -63,11 +59,10 @@ module Capybara
63
59
  end
64
60
 
65
61
  class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
66
-
67
62
  private
68
63
 
69
64
  def match(_expected, actual)
70
- @evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
65
+ @evaluator = CapybaraEvaluator.new(actual)
71
66
  syncer = sync_element(actual)
72
67
  begin
73
68
  syncer.synchronize do
@@ -1,56 +1,25 @@
1
1
  # frozen_string_literal: true
2
- if RSpec::Core::Version::STRING.to_f >= 3.0
3
- RSpec.shared_context "Capybara Features", capybara_feature: true do
4
- instance_eval do
5
- alias background before
6
- alias given let
7
- alias given! let!
8
- end
9
- end
10
2
 
11
- # ensure shared_context is included if default shared_context_metadata_behavior is changed
12
- if RSpec::Core::Version::STRING.to_f >= 3.5
13
- RSpec.configure do |config|
14
- config.include_context "Capybara Features", capybara_feature: true
15
- end
3
+ RSpec.shared_context "Capybara Features", capybara_feature: true do
4
+ instance_eval do
5
+ alias background before
6
+ alias given let
7
+ alias given! let!
16
8
  end
9
+ end
17
10
 
11
+ # ensure shared_context is included if default shared_context_metadata_behavior is changed
12
+ if RSpec::Core::Version::STRING.to_f >= 3.5
18
13
  RSpec.configure do |config|
19
- config.alias_example_group_to :feature, capybara_feature: true, type: :feature
20
- config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: "Temporarily disabled with xfeature"
21
- config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
22
- config.alias_example_to :scenario
23
- config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
24
- config.alias_example_to :fscenario, focus: true
25
- end
26
- else
27
- module Capybara
28
- module Features
29
- def self.included(base)
30
- base.instance_eval do
31
- alias :background :before
32
- alias :scenario :it
33
- alias :xscenario :xit
34
- alias :given :let
35
- alias :given! :let!
36
- alias :feature :describe
37
- end
38
- end
39
- end
40
- end
41
-
42
- def self.feature(*args, &block)
43
- options = if args.last.is_a?(Hash) then args.pop else {} end
44
- options[:capybara_feature] = true
45
- options[:type] = :feature
46
- options[:caller] ||= caller
47
- args.push(options)
48
-
49
- #call describe on RSpec in case user has expose_dsl_globally set to false
50
- RSpec.describe(*args, &block)
14
+ config.include_context "Capybara Features", capybara_feature: true
51
15
  end
16
+ end
52
17
 
53
- RSpec.configure do |config|
54
- config.include(Capybara::Features, capybara_feature: true)
55
- end
18
+ RSpec.configure do |config|
19
+ config.alias_example_group_to :feature, capybara_feature: true, type: :feature
20
+ config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: "Temporarily disabled with xfeature"
21
+ config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
22
+ config.alias_example_to :scenario
23
+ config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
24
+ config.alias_example_to :fscenario, focus: true
56
25
  end
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module RSpecMatcherProxies
4
- def all(*args)
5
+ def all(*args, &block)
5
6
  if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
6
7
  ::RSpec::Matchers::BuiltIn::All.new(*args)
7
8
  else
8
- find_all(*args)
9
+ find_all(*args, &block)
9
10
  end
10
11
  end
11
12
 
@@ -18,28 +19,43 @@ module Capybara
18
19
  end
19
20
  end
20
21
 
21
- module DSL
22
- class <<self
23
- remove_method :included
24
-
22
+ module DSLRSpecProxyInstaller
23
+ module ClassMethods
25
24
  def included(base)
26
- warn "including Capybara::DSL in the global scope is not recommended!" if base == Object
27
-
28
- if defined?(::RSpec::Matchers) && base.include?(::RSpec::Matchers)
29
- base.send(:include, ::Capybara::RSpecMatcherProxies)
25
+ if defined?(::RSpec::Matchers)
26
+ base.include(::Capybara::RSpecMatcherProxies) if base.include?(::RSpec::Matchers)
30
27
  end
28
+ super
29
+ end
30
+ end
31
+
32
+ def self.prepended(base)
33
+ class <<base
34
+ prepend ClassMethods
35
+ end
36
+ end
37
+ end
31
38
 
39
+ module RSpecMatcherProxyInstaller
40
+ module ClassMethods
41
+ def included(base)
42
+ base.include(::Capybara::RSpecMatcherProxies) if base.include?(::Capybara::DSL)
32
43
  super
33
44
  end
34
45
  end
46
+
47
+ def self.prepended(base)
48
+ class <<base
49
+ prepend ClassMethods
50
+ end
51
+ end
35
52
  end
53
+
54
+ DSL.prepend ::Capybara::DSLRSpecProxyInstaller
36
55
  end
37
56
 
38
57
  if defined?(::RSpec::Matchers)
39
- module ::RSpec::Matchers
40
- def self.included(base)
41
- base.send(:include, ::Capybara::RSpecMatcherProxies) if base.include?(::Capybara::DSL)
42
- super
43
- end
58
+ module ::RSpec::Matchers
59
+ prepend ::Capybara::RSpecMatcherProxyInstaller
44
60
  end
45
61
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module RSpecMatchers
4
5
  class Matcher
5
- if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.0'))
6
+ if defined?(::RSpec::Expectations::Version)
6
7
  require 'capybara/rspec/compound'
7
8
  include ::Capybara::RSpecMatchers::Compound
8
9
  end
@@ -10,18 +11,15 @@ module Capybara
10
11
  attr_reader :failure_message, :failure_message_when_negated
11
12
 
12
13
  def wrap(actual)
13
- @context_el = if actual.respond_to?("has_selector?")
14
+ actual = actual.to_capybara_node if actual.respond_to?(:to_capybara_node)
15
+ @context_el = if actual.respond_to?(:has_selector?)
14
16
  actual
15
17
  else
16
18
  Capybara.string(actual.to_s)
17
19
  end
18
20
  end
19
21
 
20
- # RSpec 2 compatibility:
21
- def failure_message_for_should; failure_message end
22
- def failure_message_for_should_not; failure_message_when_negated end
23
-
24
- private
22
+ private
25
23
 
26
24
  def wrap_matches?(actual)
27
25
  yield(wrap(actual))
@@ -65,11 +63,11 @@ module Capybara
65
63
  end
66
64
 
67
65
  def matches?(actual)
68
- wrap_matches?(actual){ |el| el.assert_selector(*@args, &@filter_block) }
66
+ wrap_matches?(actual) { |el| el.assert_selector(*@args, &@filter_block) }
69
67
  end
70
68
 
71
69
  def does_not_match?(actual)
72
- wrap_does_not_match?(actual){ |el| el.assert_no_selector(*@args, &@filter_block) }
70
+ wrap_does_not_match?(actual) { |el| el.assert_no_selector(*@args, &@filter_block) }
73
71
  end
74
72
 
75
73
  def description
@@ -88,10 +86,10 @@ module Capybara
88
86
  end
89
87
 
90
88
  def matches?(actual)
91
- wrap_matches?(actual){ |el| el.assert_all_of_selectors(*@args, &@filter_block) }
89
+ wrap_matches?(actual) { |el| el.assert_all_of_selectors(*@args, &@filter_block) }
92
90
  end
93
91
 
94
- def does_not_match?(actual)
92
+ def does_not_match?(_actual)
95
93
  raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
96
94
  end
97
95
 
@@ -107,10 +105,10 @@ module Capybara
107
105
  end
108
106
 
109
107
  def matches?(actual)
110
- wrap_matches?(actual){ |el| el.assert_none_of_selectors(*@args, &@filter_block) }
108
+ wrap_matches?(actual) { |el| el.assert_none_of_selectors(*@args, &@filter_block) }
111
109
  end
112
110
 
113
- def does_not_match?(actual)
111
+ def does_not_match?(_actual)
114
112
  raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
115
113
  end
116
114
 
@@ -138,15 +136,9 @@ module Capybara
138
136
  end
139
137
 
140
138
  class HaveText < Matcher
141
- attr_reader :type, :content, :options
142
-
143
139
  def initialize(*args)
144
140
  @args = args.dup
145
-
146
- # are set just for backwards compatability
147
- @type = args.shift if args.first.is_a?(Symbol)
148
- @content = args.shift
149
- @options = (args.first.is_a?(Hash))? args.first : {}
141
+ @content = args[0].is_a?(Symbol) ? args[1] : args[0]
150
142
  end
151
143
 
152
144
  def matches?(actual)
@@ -158,7 +150,7 @@ module Capybara
158
150
  end
159
151
 
160
152
  def description
161
- "text #{format(content)}"
153
+ "text #{format(@content)}"
162
154
  end
163
155
 
164
156
  def format(content)
@@ -168,8 +160,6 @@ module Capybara
168
160
  end
169
161
 
170
162
  class HaveTitle < Matcher
171
- attr_reader :title
172
-
173
163
  def initialize(*args)
174
164
  @args = args
175
165
 
@@ -186,17 +176,13 @@ module Capybara
186
176
  end
187
177
 
188
178
  def description
189
- "have title #{title.inspect}"
179
+ "have title #{@title.inspect}"
190
180
  end
191
181
  end
192
182
 
193
183
  class HaveCurrentPath < Matcher
194
- attr_reader :current_path
195
-
196
184
  def initialize(*args)
197
185
  @args = args
198
-
199
- # are set just for backwards compatability
200
186
  @current_path = args.first
201
187
  end
202
188
 
@@ -209,7 +195,33 @@ module Capybara
209
195
  end
210
196
 
211
197
  def description
212
- "have current path #{current_path.inspect}"
198
+ "have current path #{@current_path.inspect}"
199
+ end
200
+ end
201
+
202
+ class NegatedMatcher
203
+ def initialize(matcher)
204
+ @matcher = matcher
205
+ end
206
+
207
+ def matches?(actual)
208
+ @matcher.does_not_match?(actual)
209
+ end
210
+
211
+ def does_not_match?(actual)
212
+ @matcher.matches?(actual)
213
+ end
214
+
215
+ def description
216
+ "not #{@matcher.description}"
217
+ end
218
+
219
+ def failure_message
220
+ @matcher.failure_message_when_negated
221
+ end
222
+
223
+ def failure_message_when_negated
224
+ @matcher.failure_message
213
225
  end
214
226
  end
215
227
 
@@ -236,10 +248,6 @@ module Capybara
236
248
  def failure_message_when_negated
237
249
  "expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
238
250
  end
239
-
240
- # RSpec 2 compatibility:
241
- alias_method :failure_message_for_should, :failure_message
242
- alias_method :failure_message_for_should_not, :failure_message_when_negated
243
251
  end
244
252
 
245
253
  # RSpec matcher for whether the element(s) matching a given selector exist
@@ -265,107 +273,109 @@ module Capybara
265
273
  def match_selector(*args, &optional_filter_block)
266
274
  MatchSelector.new(*args, &optional_filter_block)
267
275
  end
268
- # defined_negated_matcher was added in RSpec 3.1 - it's syntactic sugar only since a user can do
269
- # expect(page).not_to match_selector, so not sure we really need to support not_match_selector for prior to RSpec 3.1
270
- ::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
271
-
272
276
 
273
277
  # RSpec matcher for whether elements(s) matching a given xpath selector exist
274
278
  # See {Capybara::Node::Matchers#has_xpath?}
275
- def have_xpath(xpath, options={}, &optional_filter_block)
279
+ def have_xpath(xpath, **options, &optional_filter_block)
276
280
  HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
277
281
  end
278
282
 
279
283
  # RSpec matcher for whether the current element matches a given xpath selector
280
- def match_xpath(xpath, options={}, &optional_filter_block)
284
+ def match_xpath(xpath, **options, &optional_filter_block)
281
285
  MatchSelector.new(:xpath, xpath, options, &optional_filter_block)
282
286
  end
283
287
 
284
288
  # RSpec matcher for whether elements(s) matching a given css selector exist
285
289
  # See {Capybara::Node::Matchers#has_css?}
286
- def have_css(css, options={}, &optional_filter_block)
290
+ def have_css(css, **options, &optional_filter_block)
287
291
  HaveSelector.new(:css, css, options, &optional_filter_block)
288
292
  end
289
293
 
290
294
  # RSpec matcher for whether the current element matches a given css selector
291
- def match_css(css, options={}, &optional_filter_block)
295
+ def match_css(css, **options, &optional_filter_block)
292
296
  MatchSelector.new(:css, css, options, &optional_filter_block)
293
297
  end
294
298
 
295
- # RSpec matcher for text on the page
299
+ # RSpec matcher for text content
296
300
  # See {Capybara::SessionMatchers#assert_text}
297
301
  def have_text(*args)
298
302
  HaveText.new(*args)
299
303
  end
300
304
  alias_method :have_content, :have_text
301
305
 
302
- def have_title(title, options = {})
306
+ def have_title(title, **options)
303
307
  HaveTitle.new(title, options)
304
308
  end
305
309
 
306
310
  # RSpec matcher for the current path
307
311
  # See {Capybara::SessionMatchers#assert_current_path}
308
- def have_current_path(path, options = {})
312
+ def have_current_path(path, **options)
309
313
  HaveCurrentPath.new(path, options)
310
314
  end
311
315
 
312
316
  # RSpec matcher for links
313
317
  # See {Capybara::Node::Matchers#has_link?}
314
- def have_link(locator=nil, options={}, &optional_filter_block)
315
- locator, options = nil, locator if locator.is_a? Hash
318
+ def have_link(locator = nil, **options, &optional_filter_block)
316
319
  HaveSelector.new(:link, locator, options, &optional_filter_block)
317
320
  end
318
321
 
319
322
  # RSpec matcher for buttons
320
323
  # See {Capybara::Node::Matchers#has_button?}
321
- def have_button(locator=nil, options={}, &optional_filter_block)
322
- locator, options = nil, locator if locator.is_a? Hash
324
+ def have_button(locator = nil, **options, &optional_filter_block)
323
325
  HaveSelector.new(:button, locator, options, &optional_filter_block)
324
326
  end
325
327
 
326
328
  # RSpec matcher for links
327
329
  # See {Capybara::Node::Matchers#has_field?}
328
- def have_field(locator=nil, options={}, &optional_filter_block)
329
- locator, options = nil, locator if locator.is_a? Hash
330
+ def have_field(locator = nil, **options, &optional_filter_block)
330
331
  HaveSelector.new(:field, locator, options, &optional_filter_block)
331
332
  end
332
333
 
333
334
  # RSpec matcher for checked fields
334
335
  # See {Capybara::Node::Matchers#has_checked_field?}
335
- def have_checked_field(locator=nil, options={}, &optional_filter_block)
336
- locator, options = nil, locator if locator.is_a? Hash
336
+ def have_checked_field(locator = nil, **options, &optional_filter_block)
337
337
  HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block)
338
338
  end
339
339
 
340
340
  # RSpec matcher for unchecked fields
341
341
  # See {Capybara::Node::Matchers#has_unchecked_field?}
342
- def have_unchecked_field(locator=nil, options={}, &optional_filter_block)
343
- locator, options = nil, locator if locator.is_a? Hash
342
+ def have_unchecked_field(locator = nil, **options, &optional_filter_block)
344
343
  HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block)
345
344
  end
346
345
 
347
346
  # RSpec matcher for select elements
348
347
  # See {Capybara::Node::Matchers#has_select?}
349
- def have_select(locator=nil, options={}, &optional_filter_block)
350
- locator, options = nil, locator if locator.is_a? Hash
348
+ def have_select(locator = nil, **options, &optional_filter_block)
351
349
  HaveSelector.new(:select, locator, options, &optional_filter_block)
352
350
  end
353
351
 
354
352
  # RSpec matcher for table elements
355
353
  # See {Capybara::Node::Matchers#has_table?}
356
- def have_table(locator=nil, options={}, &optional_filter_block)
357
- locator, options = nil, locator if locator.is_a? Hash
354
+ def have_table(locator = nil, **options, &optional_filter_block)
358
355
  HaveSelector.new(:table, locator, options, &optional_filter_block)
359
356
  end
360
357
 
358
+ %w[selector css xpath text title current_path link button field checked_field unchecked_field select table].each do |matcher_type|
359
+ define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
360
+ NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
361
+ end
362
+ end
363
+ alias_method :have_no_content, :have_no_text
364
+
365
+ %w[selector css xpath].each do |matcher_type|
366
+ define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
367
+ NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
368
+ end
369
+ end
370
+
361
371
  ##
362
372
  # Wait for window to become closed.
363
373
  # @example
364
374
  # expect(window).to become_closed(wait: 0.8)
365
375
  # @param options [Hash] optional param
366
376
  # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum wait time
367
- def become_closed(options = {})
377
+ def become_closed(**options)
368
378
  BecomeClosed.new(options)
369
379
  end
370
380
  end
371
- end
381
+ end