capybara 2.5.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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