capybara 2.5.0 → 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +5 -5
  2. data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
  3. data/.yard/templates_custom/default/class/html/setup.rb +17 -0
  4. data/.yard/yard_extensions.rb +78 -0
  5. data/.yardopts +1 -0
  6. data/History.md +413 -10
  7. data/License.txt +1 -1
  8. data/README.md +237 -130
  9. data/lib/capybara/config.rb +132 -0
  10. data/lib/capybara/cucumber.rb +3 -1
  11. data/lib/capybara/driver/base.rb +27 -6
  12. data/lib/capybara/driver/node.rb +14 -5
  13. data/lib/capybara/dsl.rb +2 -3
  14. data/lib/capybara/helpers.rb +13 -65
  15. data/lib/capybara/minitest/spec.rb +177 -0
  16. data/lib/capybara/minitest.rb +278 -0
  17. data/lib/capybara/node/actions.rb +180 -24
  18. data/lib/capybara/node/base.rb +17 -5
  19. data/lib/capybara/node/document.rb +5 -0
  20. data/lib/capybara/node/document_matchers.rb +15 -14
  21. data/lib/capybara/node/element.rb +55 -7
  22. data/lib/capybara/node/finders.rb +179 -67
  23. data/lib/capybara/node/matchers.rb +301 -105
  24. data/lib/capybara/node/simple.rb +15 -4
  25. data/lib/capybara/queries/ancestor_query.rb +25 -0
  26. data/lib/capybara/queries/base_query.rb +69 -3
  27. data/lib/capybara/queries/current_path_query.rb +17 -8
  28. data/lib/capybara/queries/match_query.rb +19 -0
  29. data/lib/capybara/queries/selector_query.rb +251 -0
  30. data/lib/capybara/queries/sibling_query.rb +25 -0
  31. data/lib/capybara/queries/text_query.rb +67 -16
  32. data/lib/capybara/queries/title_query.rb +4 -2
  33. data/lib/capybara/query.rb +3 -131
  34. data/lib/capybara/rack_test/browser.rb +14 -5
  35. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  36. data/lib/capybara/rack_test/driver.rb +15 -8
  37. data/lib/capybara/rack_test/form.rb +34 -12
  38. data/lib/capybara/rack_test/node.rb +29 -12
  39. data/lib/capybara/rails.rb +3 -3
  40. data/lib/capybara/result.rb +104 -9
  41. data/lib/capybara/rspec/compound.rb +95 -0
  42. data/lib/capybara/rspec/features.rb +17 -6
  43. data/lib/capybara/rspec/matcher_proxies.rb +45 -0
  44. data/lib/capybara/rspec/matchers.rb +199 -80
  45. data/lib/capybara/rspec.rb +4 -2
  46. data/lib/capybara/selector/css.rb +30 -0
  47. data/lib/capybara/selector/filter.rb +20 -0
  48. data/lib/capybara/selector/filter_set.rb +74 -0
  49. data/lib/capybara/selector/filters/base.rb +33 -0
  50. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  51. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  52. data/lib/capybara/selector/selector.rb +276 -0
  53. data/lib/capybara/selector.rb +452 -157
  54. data/lib/capybara/selenium/driver.rb +282 -81
  55. data/lib/capybara/selenium/node.rb +144 -46
  56. data/lib/capybara/server.rb +59 -16
  57. data/lib/capybara/session/config.rb +114 -0
  58. data/lib/capybara/session/matchers.rb +29 -19
  59. data/lib/capybara/session.rb +378 -143
  60. data/lib/capybara/spec/fixtures/no_extension +1 -0
  61. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  62. data/lib/capybara/spec/public/jquery.js +4 -9045
  63. data/lib/capybara/spec/public/test.js +45 -11
  64. data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
  65. data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
  66. data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
  67. data/lib/capybara/spec/session/all_spec.rb +45 -32
  68. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  69. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
  70. data/lib/capybara/spec/session/assert_current_path.rb +15 -2
  71. data/lib/capybara/spec/session/assert_selector.rb +29 -28
  72. data/lib/capybara/spec/session/assert_text.rb +59 -20
  73. data/lib/capybara/spec/session/assert_title.rb +25 -11
  74. data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
  75. data/lib/capybara/spec/session/body_spec.rb +1 -0
  76. data/lib/capybara/spec/session/check_spec.rb +90 -14
  77. data/lib/capybara/spec/session/choose_spec.rb +31 -5
  78. data/lib/capybara/spec/session/click_button_spec.rb +20 -9
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
  80. data/lib/capybara/spec/session/click_link_spec.rb +39 -15
  81. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  82. data/lib/capybara/spec/session/current_url_spec.rb +12 -3
  83. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
  84. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
  85. data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
  86. data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
  87. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  88. data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
  89. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
  90. data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
  91. data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
  92. data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
  93. data/lib/capybara/spec/session/find_button_spec.rb +43 -2
  94. data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
  95. data/lib/capybara/spec/session/find_field_spec.rb +42 -6
  96. data/lib/capybara/spec/session/find_link_spec.rb +22 -3
  97. data/lib/capybara/spec/session/find_spec.rb +103 -57
  98. data/lib/capybara/spec/session/first_spec.rb +34 -18
  99. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
  100. data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
  101. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  102. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  103. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  104. data/lib/capybara/spec/session/has_button_spec.rb +17 -8
  105. data/lib/capybara/spec/session/has_css_spec.rb +85 -73
  106. data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
  107. data/lib/capybara/spec/session/has_field_spec.rb +93 -58
  108. data/lib/capybara/spec/session/has_link_spec.rb +9 -8
  109. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  110. data/lib/capybara/spec/session/has_select_spec.rb +159 -59
  111. data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
  112. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  113. data/lib/capybara/spec/session/has_text_spec.rb +27 -12
  114. data/lib/capybara/spec/session/has_title_spec.rb +22 -4
  115. data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
  116. data/lib/capybara/spec/session/headers.rb +2 -1
  117. data/lib/capybara/spec/session/html_spec.rb +4 -3
  118. data/lib/capybara/spec/session/node_spec.rb +198 -38
  119. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  120. data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
  121. data/lib/capybara/spec/session/response_code.rb +2 -1
  122. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  123. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
  124. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  125. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  126. data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
  127. data/lib/capybara/spec/session/select_spec.rb +34 -32
  128. data/lib/capybara/spec/session/selectors_spec.rb +65 -0
  129. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  130. data/lib/capybara/spec/session/text_spec.rb +4 -4
  131. data/lib/capybara/spec/session/title_spec.rb +2 -1
  132. data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
  133. data/lib/capybara/spec/session/unselect_spec.rb +17 -16
  134. data/lib/capybara/spec/session/visit_spec.rb +77 -2
  135. data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
  136. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  137. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  138. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
  139. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
  140. data/lib/capybara/spec/session/window/window_spec.rb +36 -29
  141. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  142. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
  143. data/lib/capybara/spec/session/within_spec.rb +14 -6
  144. data/lib/capybara/spec/spec_helper.rb +37 -4
  145. data/lib/capybara/spec/test_app.rb +15 -3
  146. data/lib/capybara/spec/views/buttons.erb +1 -0
  147. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  148. data/lib/capybara/spec/views/form.erb +169 -9
  149. data/lib/capybara/spec/views/frame_child.erb +10 -2
  150. data/lib/capybara/spec/views/frame_one.erb +2 -1
  151. data/lib/capybara/spec/views/frame_parent.erb +3 -2
  152. data/lib/capybara/spec/views/frame_two.erb +2 -1
  153. data/lib/capybara/spec/views/header_links.erb +1 -0
  154. data/lib/capybara/spec/views/host_links.erb +1 -0
  155. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  156. data/lib/capybara/spec/views/path.erb +1 -0
  157. data/lib/capybara/spec/views/popup_one.erb +1 -0
  158. data/lib/capybara/spec/views/popup_two.erb +1 -0
  159. data/lib/capybara/spec/views/postback.erb +2 -1
  160. data/lib/capybara/spec/views/tables.erb +1 -0
  161. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  162. data/lib/capybara/spec/views/with_count.erb +2 -1
  163. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  164. data/lib/capybara/spec/views/with_hover.erb +7 -1
  165. data/lib/capybara/spec/views/with_html.erb +40 -2
  166. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  167. data/lib/capybara/spec/views/with_js.erb +32 -1
  168. data/lib/capybara/spec/views/with_scope.erb +1 -0
  169. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  170. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  171. data/lib/capybara/spec/views/with_title.erb +2 -1
  172. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  173. data/lib/capybara/spec/views/with_windows.erb +7 -0
  174. data/lib/capybara/spec/views/within_frames.erb +3 -2
  175. data/lib/capybara/version.rb +2 -1
  176. data/lib/capybara/window.rb +20 -3
  177. data/lib/capybara.rb +189 -93
  178. data/spec/basic_node_spec.rb +7 -6
  179. data/spec/capybara_spec.rb +90 -4
  180. data/spec/dsl_spec.rb +3 -1
  181. data/spec/filter_set_spec.rb +28 -0
  182. data/spec/fixtures/capybara.csv +1 -0
  183. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
  184. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
  185. data/spec/minitest_spec.rb +130 -0
  186. data/spec/minitest_spec_spec.rb +135 -0
  187. data/spec/per_session_config_spec.rb +67 -0
  188. data/spec/rack_test_spec.rb +50 -7
  189. data/spec/result_spec.rb +76 -0
  190. data/spec/rspec/features_spec.rb +21 -8
  191. data/spec/rspec/scenarios_spec.rb +21 -0
  192. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
  193. data/spec/rspec/views_spec.rb +5 -0
  194. data/spec/rspec_matchers_spec.rb +46 -0
  195. data/spec/rspec_spec.rb +79 -1
  196. data/spec/selector_spec.rb +199 -0
  197. data/spec/selenium_spec_chrome.rb +54 -9
  198. data/spec/selenium_spec_firefox.rb +68 -0
  199. data/spec/selenium_spec_marionette.rb +127 -0
  200. data/spec/server_spec.rb +102 -14
  201. data/spec/session_spec.rb +54 -0
  202. data/spec/shared_selenium_session.rb +215 -0
  203. data/spec/spec_helper.rb +7 -0
  204. metadata +140 -15
  205. data/spec/selenium_spec.rb +0 -128
@@ -0,0 +1,95 @@
1
+ module Capybara
2
+ module RSpecMatchers
3
+ module Compound
4
+ include ::RSpec::Matchers::Composable
5
+
6
+ def and(matcher)
7
+ Capybara::RSpecMatchers::Compound::And.new(self,matcher)
8
+ end
9
+
10
+ def and_then(matcher)
11
+ ::RSpec::Matchers::BuiltIn::Compound::And.new(self, matcher)
12
+ end
13
+
14
+ def or(matcher)
15
+ Capybara::RSpecMatchers::Compound::Or.new(self, matcher)
16
+ end
17
+
18
+
19
+ class CapybaraEvaluator
20
+ def initialize(actual, matcher_1, matcher_2)
21
+ @actual = actual
22
+ @matcher_1 = matcher_1
23
+ @matcher_2 = matcher_2
24
+ @match_results = Hash.new { |h, matcher| h[matcher] = matcher.matches?(@actual) }
25
+ end
26
+
27
+ def matcher_matches?(matcher)
28
+ @match_results[matcher]
29
+ end
30
+
31
+ def reset
32
+ @match_results.clear
33
+ end
34
+ end
35
+
36
+ class And < ::RSpec::Matchers::BuiltIn::Compound::And
37
+
38
+ private
39
+
40
+ def match(_expected, actual)
41
+ @evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
42
+ syncer = sync_element(actual)
43
+ begin
44
+ syncer.synchronize do
45
+ @evaluator.reset
46
+ raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].all?
47
+ true
48
+ end
49
+ rescue
50
+ false
51
+ end
52
+ end
53
+
54
+ def sync_element(el)
55
+ if el.respond_to? :synchronize
56
+ el
57
+ elsif el.respond_to? :current_scope
58
+ el.current_scope
59
+ else
60
+ Capybara.string(el)
61
+ end
62
+ end
63
+ end
64
+
65
+ class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
66
+
67
+ private
68
+
69
+ def match(_expected, actual)
70
+ @evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
71
+ syncer = sync_element(actual)
72
+ begin
73
+ syncer.synchronize do
74
+ @evaluator.reset
75
+ raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].any?
76
+ true
77
+ end
78
+ rescue
79
+ false
80
+ end
81
+ end
82
+
83
+ def sync_element(el)
84
+ if el.respond_to? :synchronize
85
+ el
86
+ elsif el.respond_to? :current_scope
87
+ el.current_scope
88
+ else
89
+ Capybara.string(el)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  if RSpec::Core::Version::STRING.to_f >= 3.0
2
- RSpec.shared_context "Capybara Features", :capybara_feature => true do
3
+ RSpec.shared_context "Capybara Features", capybara_feature: true do
3
4
  instance_eval do
4
5
  alias background before
5
6
  alias given let
@@ -7,11 +8,20 @@ if RSpec::Core::Version::STRING.to_f >= 3.0
7
8
  end
8
9
  end
9
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
13
+ RSpec.configure do |config|
14
+ config.include_context "Capybara Features", capybara_feature: true
15
+ end
16
+ end
17
+
10
18
  RSpec.configure do |config|
11
- config.alias_example_group_to :feature, :capybara_feature => true, :type => :feature
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
12
22
  config.alias_example_to :scenario
13
- config.alias_example_to :xscenario, :skip => "Temporarily disabled with xscenario"
14
- config.alias_example_to :fscenario, :focus => true
23
+ config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
24
+ config.alias_example_to :fscenario, focus: true
15
25
  end
16
26
  else
17
27
  module Capybara
@@ -29,7 +39,6 @@ else
29
39
  end
30
40
  end
31
41
 
32
-
33
42
  def self.feature(*args, &block)
34
43
  options = if args.last.is_a?(Hash) then args.pop else {} end
35
44
  options[:capybara_feature] = true
@@ -41,5 +50,7 @@ else
41
50
  RSpec.describe(*args, &block)
42
51
  end
43
52
 
44
- RSpec.configuration.include Capybara::Features, :capybara_feature => true
53
+ RSpec.configure do |config|
54
+ config.include(Capybara::Features, capybara_feature: true)
55
+ end
45
56
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ module Capybara
3
+ module RSpecMatcherProxies
4
+ def all(*args)
5
+ if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
6
+ ::RSpec::Matchers::BuiltIn::All.new(*args)
7
+ else
8
+ find_all(*args)
9
+ end
10
+ end
11
+
12
+ def within(*args)
13
+ if block_given?
14
+ within_element(*args, &Proc.new)
15
+ else
16
+ be_within(*args)
17
+ end
18
+ end
19
+ end
20
+
21
+ module DSL
22
+ class <<self
23
+ remove_method :included
24
+
25
+ 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)
30
+ end
31
+
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ 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
44
+ end
45
+ end
@@ -1,56 +1,145 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module RSpecMatchers
3
4
  class Matcher
4
- include ::RSpec::Matchers::Composable if defined?(::RSpec::Expectations::Version) && RSpec::Expectations::Version::STRING.to_f >= 3.0
5
+ if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.0'))
6
+ require 'capybara/rspec/compound'
7
+ include ::Capybara::RSpecMatchers::Compound
8
+ end
9
+
10
+ attr_reader :failure_message, :failure_message_when_negated
5
11
 
6
12
  def wrap(actual)
7
- if actual.respond_to?("has_selector?")
13
+ @context_el = if actual.respond_to?("has_selector?")
8
14
  actual
9
15
  else
10
16
  Capybara.string(actual.to_s)
11
17
  end
12
18
  end
13
- end
14
19
 
15
- class HaveSelector < Matcher
16
- attr_reader :failure_message, :failure_message_when_negated
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
17
23
 
18
- def initialize(*args)
19
- @args = args
20
- end
24
+ private
21
25
 
22
- def matches?(actual)
23
- wrap(actual).assert_selector(*@args)
26
+ def wrap_matches?(actual)
27
+ yield(wrap(actual))
24
28
  rescue Capybara::ExpectationNotMet => e
25
29
  @failure_message = e.message
26
30
  return false
27
31
  end
28
32
 
29
- def does_not_match?(actual)
30
- wrap(actual).assert_no_selector(*@args)
33
+ def wrap_does_not_match?(actual)
34
+ yield(wrap(actual))
31
35
  rescue Capybara::ExpectationNotMet => e
32
36
  @failure_message_when_negated = e.message
33
37
  return false
34
38
  end
35
39
 
40
+ def session_query_args
41
+ if @args.last.is_a? Hash
42
+ @args.last[:session_options] = session_options
43
+ else
44
+ @args.push(session_options: session_options)
45
+ end
46
+ @args
47
+ end
48
+
49
+ def session_options
50
+ @context_el ||= nil
51
+ if @context_el.respond_to? :session_options
52
+ @context_el.session_options
53
+ elsif @context_el.respond_to? :current_scope
54
+ @context_el.current_scope.session_options
55
+ else
56
+ Capybara.session_options
57
+ end
58
+ end
59
+ end
60
+
61
+ class HaveSelector < Matcher
62
+ def initialize(*args, &filter_block)
63
+ @args = args
64
+ @filter_block = filter_block
65
+ end
66
+
67
+ def matches?(actual)
68
+ wrap_matches?(actual){ |el| el.assert_selector(*@args, &@filter_block) }
69
+ end
70
+
71
+ def does_not_match?(actual)
72
+ wrap_does_not_match?(actual){ |el| el.assert_no_selector(*@args, &@filter_block) }
73
+ end
74
+
36
75
  def description
37
76
  "have #{query.description}"
38
77
  end
39
78
 
40
79
  def query
41
- @query ||= Capybara::Query.new(*@args)
80
+ @query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
42
81
  end
82
+ end
43
83
 
44
- # RSpec 2 compatibility:
45
- alias_method :failure_message_for_should, :failure_message
46
- alias_method :failure_message_for_should_not, :failure_message_when_negated
84
+ class HaveAllSelectors < Matcher
85
+ def initialize(*args, &filter_block)
86
+ @args = args
87
+ @filter_block = filter_block
88
+ end
89
+
90
+ def matches?(actual)
91
+ wrap_matches?(actual){ |el| el.assert_all_of_selectors(*@args, &@filter_block) }
92
+ end
93
+
94
+ def does_not_match?(actual)
95
+ raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
96
+ end
97
+
98
+ def description
99
+ "have all selectors"
100
+ end
101
+ end
102
+
103
+ class HaveNoSelectors < Matcher
104
+ def initialize(*args, &filter_block)
105
+ @args = args
106
+ @filter_block = filter_block
107
+ end
108
+
109
+ def matches?(actual)
110
+ wrap_matches?(actual){ |el| el.assert_none_of_selectors(*@args, &@filter_block) }
111
+ end
112
+
113
+ def does_not_match?(actual)
114
+ raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
115
+ end
116
+
117
+ def description
118
+ "have no selectors"
119
+ end
120
+ end
121
+
122
+ class MatchSelector < HaveSelector
123
+ def matches?(actual)
124
+ wrap_matches?(actual) { |el| el.assert_matches_selector(*@args, &@filter_block) }
125
+ end
126
+
127
+ def does_not_match?(actual)
128
+ wrap_does_not_match?(actual) { |el| el.assert_not_matches_selector(*@args, &@filter_block) }
129
+ end
130
+
131
+ def description
132
+ "match #{query.description}"
133
+ end
134
+
135
+ def query
136
+ @query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
137
+ end
47
138
  end
48
139
 
49
140
  class HaveText < Matcher
50
141
  attr_reader :type, :content, :options
51
142
 
52
- attr_reader :failure_message, :failure_message_when_negated
53
-
54
143
  def initialize(*args)
55
144
  @args = args.dup
56
145
 
@@ -61,17 +150,11 @@ module Capybara
61
150
  end
62
151
 
63
152
  def matches?(actual)
64
- wrap(actual).assert_text(*@args)
65
- rescue Capybara::ExpectationNotMet => e
66
- @failure_message = e.message
67
- return false
153
+ wrap_matches?(actual) { |el| el.assert_text(*@args) }
68
154
  end
69
155
 
70
156
  def does_not_match?(actual)
71
- wrap(actual).assert_no_text(*@args)
72
- rescue Capybara::ExpectationNotMet => e
73
- @failure_message_when_negated = e.message
74
- return false
157
+ wrap_does_not_match?(actual) { |el| el.assert_no_text(*@args) }
75
158
  end
76
159
 
77
160
  def description
@@ -82,17 +165,11 @@ module Capybara
82
165
  content = Capybara::Helpers.normalize_whitespace(content) unless content.is_a? Regexp
83
166
  content.inspect
84
167
  end
85
-
86
- # RSpec 2 compatibility:
87
- alias_method :failure_message_for_should, :failure_message
88
- alias_method :failure_message_for_should_not, :failure_message_when_negated
89
168
  end
90
169
 
91
170
  class HaveTitle < Matcher
92
171
  attr_reader :title
93
172
 
94
- attr_reader :failure_message, :failure_message_when_negated
95
-
96
173
  def initialize(*args)
97
174
  @args = args
98
175
 
@@ -101,33 +178,21 @@ module Capybara
101
178
  end
102
179
 
103
180
  def matches?(actual)
104
- wrap(actual).assert_title(*@args)
105
- rescue Capybara::ExpectationNotMet => e
106
- @failure_message = e.message
107
- return false
181
+ wrap_matches?(actual) { |el| el.assert_title(*@args) }
108
182
  end
109
183
 
110
184
  def does_not_match?(actual)
111
- wrap(actual).assert_no_title(*@args)
112
- rescue Capybara::ExpectationNotMet => e
113
- @failure_message_when_negated = e.message
114
- return false
185
+ wrap_does_not_match?(actual) { |el| el.assert_no_title(*@args) }
115
186
  end
116
187
 
117
188
  def description
118
189
  "have title #{title.inspect}"
119
190
  end
120
-
121
- # RSpec 2 compatibility:
122
- alias_method :failure_message_for_should, :failure_message
123
- alias_method :failure_message_for_should_not, :failure_message_when_negated
124
191
  end
125
192
 
126
193
  class HaveCurrentPath < Matcher
127
194
  attr_reader :current_path
128
195
 
129
- attr_reader :failure_message, :failure_message_when_negated
130
-
131
196
  def initialize(*args)
132
197
  @args = args
133
198
 
@@ -136,35 +201,26 @@ module Capybara
136
201
  end
137
202
 
138
203
  def matches?(actual)
139
- wrap(actual).assert_current_path(*@args)
140
- rescue Capybara::ExpectationNotMet => e
141
- @failure_message = e.message
142
- return false
204
+ wrap_matches?(actual) { |el| el.assert_current_path(*@args) }
143
205
  end
144
206
 
145
207
  def does_not_match?(actual)
146
- wrap(actual).assert_no_current_path(*@args)
147
- rescue Capybara::ExpectationNotMet => e
148
- @failure_message_when_negated = e.message
149
- return false
208
+ wrap_does_not_match?(actual) { |el| el.assert_no_current_path(*@args) }
150
209
  end
151
210
 
152
211
  def description
153
212
  "have current path #{current_path.inspect}"
154
213
  end
155
-
156
- # RSpec 2 compatibility:
157
- alias_method :failure_message_for_should, :failure_message
158
- alias_method :failure_message_for_should_not, :failure_message_when_negated
159
214
  end
160
215
 
161
216
  class BecomeClosed
162
217
  def initialize(options)
163
- @wait_time = Capybara::Query.new(options).wait
218
+ @options = options
164
219
  end
165
220
 
166
221
  def matches?(window)
167
222
  @window = window
223
+ @wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time)
168
224
  start_time = Capybara::Helpers.monotonic_time
169
225
  while window.exists?
170
226
  return false if (Capybara::Helpers.monotonic_time - start_time) > @wait_time
@@ -186,18 +242,58 @@ module Capybara
186
242
  alias_method :failure_message_for_should_not, :failure_message_when_negated
187
243
  end
188
244
 
189
- def have_selector(*args)
190
- HaveSelector.new(*args)
245
+ # RSpec matcher for whether the element(s) matching a given selector exist
246
+ # See {Capybara::Node::Matcher#assert_selector}
247
+ def have_selector(*args, &optional_filter_block)
248
+ HaveSelector.new(*args, &optional_filter_block)
249
+ end
250
+
251
+ # RSpec matcher for whether the element(s) matching a group of selectors exist
252
+ # See {Capybara::Node::Matcher#assert_all_of_selectors}
253
+ def have_all_of_selectors(*args, &optional_filter_block)
254
+ HaveAllSelectors.new(*args, &optional_filter_block)
255
+ end
256
+
257
+ # RSpec matcher for whether no element(s) matching a group of selectors exist
258
+ # See {Capybara::Node::Matcher#assert_none_of_selectors}
259
+ def have_none_of_selectors(*args, &optional_filter_block)
260
+ HaveNoSelectors.new(*args, &optional_filter_block)
261
+ end
262
+
263
+ # RSpec matcher for whether the current element matches a given selector
264
+ # See {Capybara::Node::Matchers#assert_matches_selector}
265
+ def match_selector(*args, &optional_filter_block)
266
+ MatchSelector.new(*args, &optional_filter_block)
267
+ 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
+
273
+ # RSpec matcher for whether elements(s) matching a given xpath selector exist
274
+ # See {Capybara::Node::Matchers#has_xpath?}
275
+ def have_xpath(xpath, options={}, &optional_filter_block)
276
+ HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
277
+ end
278
+
279
+ # RSpec matcher for whether the current element matches a given xpath selector
280
+ def match_xpath(xpath, options={}, &optional_filter_block)
281
+ MatchSelector.new(:xpath, xpath, options, &optional_filter_block)
191
282
  end
192
283
 
193
- def have_xpath(xpath, options={})
194
- HaveSelector.new(:xpath, xpath, options)
284
+ # RSpec matcher for whether elements(s) matching a given css selector exist
285
+ # See {Capybara::Node::Matchers#has_css?}
286
+ def have_css(css, options={}, &optional_filter_block)
287
+ HaveSelector.new(:css, css, options, &optional_filter_block)
195
288
  end
196
289
 
197
- def have_css(css, options={})
198
- HaveSelector.new(:css, css, options)
290
+ # RSpec matcher for whether the current element matches a given css selector
291
+ def match_css(css, options={}, &optional_filter_block)
292
+ MatchSelector.new(:css, css, options, &optional_filter_block)
199
293
  end
200
294
 
295
+ # RSpec matcher for text on the page
296
+ # See {Capybara::SessionMatchers#assert_text}
201
297
  def have_text(*args)
202
298
  HaveText.new(*args)
203
299
  end
@@ -207,36 +303,59 @@ module Capybara
207
303
  HaveTitle.new(title, options)
208
304
  end
209
305
 
306
+ # RSpec matcher for the current path
307
+ # See {Capybara::SessionMatchers#assert_current_path}
210
308
  def have_current_path(path, options = {})
211
309
  HaveCurrentPath.new(path, options)
212
310
  end
213
311
 
214
- def have_link(locator, options={})
215
- HaveSelector.new(:link, locator, options)
312
+ # RSpec matcher for links
313
+ # 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
316
+ HaveSelector.new(:link, locator, options, &optional_filter_block)
216
317
  end
217
318
 
218
- def have_button(locator, options={})
219
- HaveSelector.new(:button, locator, options)
319
+ # RSpec matcher for buttons
320
+ # 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
323
+ HaveSelector.new(:button, locator, options, &optional_filter_block)
220
324
  end
221
325
 
222
- def have_field(locator, options={})
223
- HaveSelector.new(:field, locator, options)
326
+ # RSpec matcher for links
327
+ # 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
+ HaveSelector.new(:field, locator, options, &optional_filter_block)
224
331
  end
225
332
 
226
- def have_checked_field(locator, options={})
227
- HaveSelector.new(:field, locator, options.merge(:checked => true))
333
+ # RSpec matcher for checked fields
334
+ # 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
337
+ HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block)
228
338
  end
229
339
 
230
- def have_unchecked_field(locator, options={})
231
- HaveSelector.new(:field, locator, options.merge(:unchecked => true))
340
+ # RSpec matcher for unchecked fields
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
344
+ HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block)
232
345
  end
233
346
 
234
- def have_select(locator, options={})
235
- HaveSelector.new(:select, locator, options)
347
+ # RSpec matcher for select elements
348
+ # 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
351
+ HaveSelector.new(:select, locator, options, &optional_filter_block)
236
352
  end
237
353
 
238
- def have_table(locator, options={})
239
- HaveSelector.new(:table, locator, options)
354
+ # RSpec matcher for table elements
355
+ # 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
358
+ HaveSelector.new(:table, locator, options, &optional_filter_block)
240
359
  end
241
360
 
242
361
  ##
@@ -249,4 +368,4 @@ module Capybara
249
368
  BecomeClosed.new(options)
250
369
  end
251
370
  end
252
- end
371
+ end
@@ -1,8 +1,9 @@
1
- require 'capybara'
2
- require 'capybara/dsl'
1
+ # frozen_string_literal: true
3
2
  require 'rspec/core'
3
+ require 'capybara/dsl'
4
4
  require 'capybara/rspec/matchers'
5
5
  require 'capybara/rspec/features'
6
+ require 'capybara/rspec/matcher_proxies'
6
7
 
7
8
  RSpec.configure do |config|
8
9
  config.include Capybara::DSL, :type => :feature
@@ -22,6 +23,7 @@ RSpec.configure do |config|
22
23
  Capybara.use_default_driver
23
24
  end
24
25
  end
26
+
25
27
  config.before do
26
28
  if self.class.include?(Capybara::DSL)
27
29
  example = fetch_current_example.call(self)
@@ -0,0 +1,30 @@
1
+ module Capybara
2
+ class Selector
3
+ class CSS
4
+ def self.escape(str)
5
+ out = String.new("")
6
+ value = str.dup
7
+ out << value.slice!(0...1) if value =~ /^[-_]/
8
+ out << if value[0] =~ NMSTART
9
+ value.slice!(0...1)
10
+ else
11
+ escape_char(value.slice!(0...1))
12
+ end
13
+ out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
14
+ out
15
+ end
16
+
17
+ def self.escape_char(c)
18
+ return "\\%06x" % c.ord() unless c =~ %r{[ -/:-~]}
19
+ "\\#{c}"
20
+ end
21
+
22
+ S = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
23
+ H = /[0-9a-fA-F]/
24
+ UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
25
+ NONASCII = /[#{S}]/
26
+ ESCAPE = /#{UNICODE}|\\[ -~#{S}]/
27
+ NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'capybara/selector/filters/node_filter'
3
+ require 'capybara/selector/filters/expression_filter'
4
+
5
+ module Capybara
6
+ class Selector
7
+ def self.const_missing(const_name)
8
+ case const_name
9
+ when :Filter
10
+ warn "DEPRECATED: Capybara::Selector::Filter is deprecated, please use Capybara::Selector::Filters::NodeFilter instead"
11
+ Filters::NodeFilter
12
+ when :ExpressionFilter
13
+ warn "DEPRECATED: Capybara::Selector::ExpressionFilter is deprecated, please use Capybara::Selector::Filters::ExpressionFilter instead"
14
+ Filters::ExpressionFilter
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end