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
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module Matchers
4
5
 
5
6
  ##
6
7
  #
7
- # Checks if a given selector is on the page or current node.
8
+ # Checks if a given selector is on the page or a descendant of the current node.
8
9
  #
9
10
  # page.has_selector?('p#foo')
10
11
  # page.has_selector?(:xpath, './/p[@id="foo"]')
@@ -13,14 +14,14 @@ module Capybara
13
14
  # By default it will check if the expression occurs at least once,
14
15
  # but a different number can be specified.
15
16
  #
16
- # page.has_selector?('p.foo', :count => 4)
17
+ # page.has_selector?('p.foo', count: 4)
17
18
  #
18
19
  # This will check if the expression occurs exactly 4 times.
19
20
  #
20
21
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
21
22
  # such as :text and :visible.
22
23
  #
23
- # page.has_selector?('li', :text => 'Horse', :visible => true)
24
+ # page.has_selector?('li', text: 'Horse', visible: true)
24
25
  #
25
26
  # has_selector? can also accept XPath expressions generated by the
26
27
  # XPath gem:
@@ -35,29 +36,29 @@ module Capybara
35
36
  # @option args [Range] :between (nil) Range of times that should contain number of times text occurs
36
37
  # @return [Boolean] If the expression exists
37
38
  #
38
- def has_selector?(*args)
39
- assert_selector(*args)
39
+ def has_selector?(*args, &optional_filter_block)
40
+ assert_selector(*args, &optional_filter_block)
40
41
  rescue Capybara::ExpectationNotMet
41
42
  return false
42
43
  end
43
44
 
44
45
  ##
45
46
  #
46
- # Checks if a given selector is not on the page or current node.
47
+ # Checks if a given selector is not on the page or a descendant of the current node.
47
48
  # Usage is identical to Capybara::Node::Matchers#has_selector?
48
49
  #
49
50
  # @param (see Capybara::Node::Finders#has_selector?)
50
51
  # @return [Boolean]
51
52
  #
52
- def has_no_selector?(*args)
53
- assert_no_selector(*args)
53
+ def has_no_selector?(*args, &optional_filter_block)
54
+ assert_no_selector(*args, &optional_filter_block)
54
55
  rescue Capybara::ExpectationNotMet
55
56
  return false
56
57
  end
57
58
 
58
59
  ##
59
60
  #
60
- # Asserts that a given selector is on the page or current node.
61
+ # Asserts that a given selector is on the page or a descendant of the current node.
61
62
  #
62
63
  # page.assert_selector('p#foo')
63
64
  # page.assert_selector(:xpath, './/p[@id="foo"]')
@@ -66,7 +67,7 @@ module Capybara
66
67
  # By default it will check if the expression occurs at least once,
67
68
  # but a different number can be specified.
68
69
  #
69
- # page.assert_selector('p#foo', :count => 4)
70
+ # page.assert_selector('p#foo', count: 4)
70
71
  #
71
72
  # This will check if the expression occurs exactly 4 times. See
72
73
  # {Capybara::Node::Finders#all} for other available result size options.
@@ -77,7 +78,7 @@ module Capybara
77
78
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
78
79
  # such as :text and :visible.
79
80
  #
80
- # page.assert_selector('li', :text => 'Horse', :visible => true)
81
+ # page.assert_selector('li', text: 'Horse', visible: true)
81
82
  #
82
83
  # `assert_selector` can also accept XPath expressions generated by the
83
84
  # XPath gem:
@@ -88,64 +89,108 @@ module Capybara
88
89
  # @option options [Integer] :count (nil) Number of times the expression should occur
89
90
  # @raise [Capybara::ExpectationNotMet] If the selector does not exist
90
91
  #
91
- def assert_selector(*args)
92
- query = Capybara::Query.new(*args)
93
- synchronize(query.wait) do
94
- result = query.resolve_for(self)
95
- matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
96
- unless matches_count && ((result.size > 0) || Capybara::Helpers.expects_none?(query.options))
92
+ def assert_selector(*args, &optional_filter_block)
93
+ _verify_selector_result(args, optional_filter_block) do |result, query|
94
+ unless result.matches_count? && ((!result.empty?) || query.expects_none?)
97
95
  raise Capybara::ExpectationNotMet, result.failure_message
98
96
  end
99
97
  end
100
- return true
98
+ end
99
+
100
+ # Asserts that all of the provided selectors are present on the given page
101
+ # or descendants of the current node. If options are provided, the assertion
102
+ # will check that each locator is present with those options as well (other than :wait).
103
+ #
104
+ # page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
105
+ # page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
106
+ #
107
+ # It accepts all options that {Capybara::Node::Finders#all} accepts,
108
+ # such as :text and :visible.
109
+ #
110
+ # The :wait option applies to all of the selectors as a group, so all of the locators must be present
111
+ # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
112
+ #
113
+ # @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, options = {})
114
+ #
115
+ def assert_all_of_selectors(*args, &optional_filter_block)
116
+ options = if args.last.is_a?(Hash) then args.pop.dup else {} end
117
+ selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
118
+ wait = options.fetch(:wait, session_options.default_max_wait_time)
119
+ synchronize(wait) do
120
+ args.each do |locator|
121
+ assert_selector(selector, locator, options, &optional_filter_block)
122
+ end
123
+ end
124
+ end
125
+
126
+ # Asserts that none of the provided selectors are present on the given page
127
+ # or descendants of the current node. If options are provided, the assertion
128
+ # will check that each locator is present with those options as well (other than :wait).
129
+ #
130
+ # page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
131
+ # page.assert_none_of_selectors(:css, '#my_div', 'a.not_clicked')
132
+ #
133
+ # It accepts all options that {Capybara::Node::Finders#all} accepts,
134
+ # such as :text and :visible.
135
+ #
136
+ # The :wait option applies to all of the selectors as a group, so none of the locators must be present
137
+ # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
138
+ #
139
+ # @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, options = {})
140
+ #
141
+ def assert_none_of_selectors(*args, &optional_filter_block)
142
+ options = if args.last.is_a?(Hash) then args.pop.dup else {} end
143
+ selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
144
+ wait = options.fetch(:wait, session_options.default_max_wait_time)
145
+ synchronize(wait) do
146
+ args.each do |locator|
147
+ assert_no_selector(selector, locator, options, &optional_filter_block)
148
+ end
149
+ end
101
150
  end
102
151
 
103
152
  ##
104
153
  #
105
- # Asserts that a given selector is not on the page or current node.
154
+ # Asserts that a given selector is not on the page or a descendant of the current node.
106
155
  # Usage is identical to Capybara::Node::Matchers#assert_selector
107
156
  #
108
157
  # Query options such as :count, :minimum, :maximum, and :between are
109
158
  # considered to be an integral part of the selector. This will return
110
159
  # true, for example, if a page contains 4 anchors but the query expects 5:
111
160
  #
112
- # page.assert_no_selector('a', :minimum => 1) # Found, raises Capybara::ExpectationNotMet
113
- # page.assert_no_selector('a', :count => 4) # Found, raises Capybara::ExpectationNotMet
114
- # page.assert_no_selector('a', :count => 5) # Not Found, returns true
161
+ # page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet
162
+ # page.assert_no_selector('a', count: 4) # Found, raises Capybara::ExpectationNotMet
163
+ # page.assert_no_selector('a', count: 5) # Not Found, returns true
115
164
  #
116
165
  # @param (see Capybara::Node::Finders#assert_selector)
117
166
  # @raise [Capybara::ExpectationNotMet] If the selector exists
118
167
  #
119
- def assert_no_selector(*args)
120
- query = Capybara::Query.new(*args)
121
- synchronize(query.wait) do
122
- result = query.resolve_for(self)
123
- matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
124
- if matches_count && ((result.size > 0) || Capybara::Helpers.expects_none?(query.options))
168
+ def assert_no_selector(*args, &optional_filter_block)
169
+ _verify_selector_result(args, optional_filter_block) do |result, query|
170
+ if result.matches_count? && ((!result.empty?) || query.expects_none?)
125
171
  raise Capybara::ExpectationNotMet, result.negative_failure_message
126
172
  end
127
173
  end
128
- return true
129
174
  end
130
175
  alias_method :refute_selector, :assert_no_selector
131
176
 
132
177
  ##
133
178
  #
134
- # Checks if a given XPath expression is on the page or current node.
179
+ # Checks if a given XPath expression is on the page or a descendant of the current node.
135
180
  #
136
181
  # page.has_xpath?('.//p[@id="foo"]')
137
182
  #
138
183
  # By default it will check if the expression occurs at least once,
139
184
  # but a different number can be specified.
140
185
  #
141
- # page.has_xpath?('.//p[@id="foo"]', :count => 4)
186
+ # page.has_xpath?('.//p[@id="foo"]', count: 4)
142
187
  #
143
188
  # This will check if the expression occurs exactly 4 times.
144
189
  #
145
190
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
146
191
  # such as :text and :visible.
147
192
  #
148
- # page.has_xpath?('.//li', :text => 'Horse', :visible => true)
193
+ # page.has_xpath?('.//li', text: 'Horse', visible: true)
149
194
  #
150
195
  # has_xpath? can also accept XPath expressions generate by the
151
196
  # XPath gem:
@@ -158,59 +203,59 @@ module Capybara
158
203
  # @option options [Integer] :count (nil) Number of times the expression should occur
159
204
  # @return [Boolean] If the expression exists
160
205
  #
161
- def has_xpath?(path, options={})
162
- has_selector?(:xpath, path, options)
206
+ def has_xpath?(path, options={}, &optional_filter_block)
207
+ has_selector?(:xpath, path, options, &optional_filter_block)
163
208
  end
164
209
 
165
210
  ##
166
211
  #
167
- # Checks if a given XPath expression is not on the page or current node.
212
+ # Checks if a given XPath expression is not on the page or a descendant of the current node.
168
213
  # Usage is identical to Capybara::Node::Matchers#has_xpath?
169
214
  #
170
215
  # @param (see Capybara::Node::Finders#has_xpath?)
171
216
  # @return [Boolean]
172
217
  #
173
- def has_no_xpath?(path, options={})
174
- has_no_selector?(:xpath, path, options)
218
+ def has_no_xpath?(path, options={}, &optional_filter_block)
219
+ has_no_selector?(:xpath, path, options, &optional_filter_block)
175
220
  end
176
221
 
177
222
  ##
178
223
  #
179
- # Checks if a given CSS selector is on the page or current node.
224
+ # Checks if a given CSS selector is on the page or a descendant of the current node.
180
225
  #
181
226
  # page.has_css?('p#foo')
182
227
  #
183
228
  # By default it will check if the selector occurs at least once,
184
229
  # but a different number can be specified.
185
230
  #
186
- # page.has_css?('p#foo', :count => 4)
231
+ # page.has_css?('p#foo', count: 4)
187
232
  #
188
233
  # This will check if the selector occurs exactly 4 times.
189
234
  #
190
235
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
191
236
  # such as :text and :visible.
192
237
  #
193
- # page.has_css?('li', :text => 'Horse', :visible => true)
238
+ # page.has_css?('li', text: 'Horse', visible: true)
194
239
  #
195
240
  # @param [String] path A CSS selector
196
241
  # @param options (see Capybara::Node::Finders#all)
197
242
  # @option options [Integer] :count (nil) Number of times the selector should occur
198
243
  # @return [Boolean] If the selector exists
199
244
  #
200
- def has_css?(path, options={})
201
- has_selector?(:css, path, options)
245
+ def has_css?(path, options={}, &optional_filter_block)
246
+ has_selector?(:css, path, options, &optional_filter_block)
202
247
  end
203
248
 
204
249
  ##
205
250
  #
206
- # Checks if a given CSS selector is not on the page or current node.
251
+ # Checks if a given CSS selector is not on the page or a descendant of the current node.
207
252
  # Usage is identical to Capybara::Node::Matchers#has_css?
208
253
  #
209
254
  # @param (see Capybara::Node::Finders#has_css?)
210
255
  # @return [Boolean]
211
256
  #
212
- def has_no_css?(path, options={})
213
- has_no_selector?(:css, path, options)
257
+ def has_no_css?(path, options={}, &optional_filter_block)
258
+ has_no_selector?(:css, path, options, &optional_filter_block)
214
259
  end
215
260
 
216
261
  ##
@@ -223,8 +268,9 @@ module Capybara
223
268
  # @option options [String, Regexp] :href The value the href attribute must be
224
269
  # @return [Boolean] Whether it exists
225
270
  #
226
- def has_link?(locator, options={})
227
- has_selector?(:link, locator, options)
271
+ def has_link?(locator=nil, options={}, &optional_filter_block)
272
+ locator, options = nil, locator if locator.is_a? Hash
273
+ has_selector?(:link, locator, options, &optional_filter_block)
228
274
  end
229
275
 
230
276
  ##
@@ -235,8 +281,9 @@ module Capybara
235
281
  # @param (see Capybara::Node::Finders#has_link?)
236
282
  # @return [Boolean] Whether it doesn't exist
237
283
  #
238
- def has_no_link?(locator, options={})
239
- has_no_selector?(:link, locator, options)
284
+ def has_no_link?(locator=nil, options={}, &optional_filter_block)
285
+ locator, options = nil, locator if locator.is_a? Hash
286
+ has_no_selector?(:link, locator, options, &optional_filter_block)
240
287
  end
241
288
 
242
289
  ##
@@ -247,8 +294,9 @@ module Capybara
247
294
  # @param [String] locator The text, value or id of a button to check for
248
295
  # @return [Boolean] Whether it exists
249
296
  #
250
- def has_button?(locator, options={})
251
- has_selector?(:button, locator, options)
297
+ def has_button?(locator=nil, options={}, &optional_filter_block)
298
+ locator, options = nil, locator if locator.is_a? Hash
299
+ has_selector?(:button, locator, options, &optional_filter_block)
252
300
  end
253
301
 
254
302
  ##
@@ -259,8 +307,9 @@ module Capybara
259
307
  # @param [String] locator The text, value or id of a button to check for
260
308
  # @return [Boolean] Whether it doesn't exist
261
309
  #
262
- def has_no_button?(locator, options={})
263
- has_no_selector?(:button, locator, options)
310
+ def has_no_button?(locator=nil, options={}, &optional_filter_block)
311
+ locator, options = nil, locator if locator.is_a? Hash
312
+ has_no_selector?(:button, locator, options, &optional_filter_block)
264
313
  end
265
314
 
266
315
  ##
@@ -272,21 +321,22 @@ module Capybara
272
321
  # HTML5 email/url/etc. fields, it's possible to specify a :with
273
322
  # option to specify the text the field should contain:
274
323
  #
275
- # page.has_field?('Name', :with => 'Jonas')
324
+ # page.has_field?('Name', with: 'Jonas')
276
325
  #
277
326
  # It is also possible to filter by the field type attribute:
278
327
  #
279
- # page.has_field?('Email', :type => 'email')
328
+ # page.has_field?('Email', type: 'email')
280
329
  #
281
330
  # Note: 'textarea' and 'select' are valid type values, matching the associated tag names.
282
331
  #
283
- # @param [String] locator The label, name or id of a field to check for
284
- # @option options [String] :with The text content of the field
285
- # @option options [String] :type The type attribute of the field
286
- # @return [Boolean] Whether it exists
332
+ # @param [String] locator The label, name or id of a field to check for
333
+ # @option options [String, Regexp] :with The text content of the field or a Regexp to match
334
+ # @option options [String] :type The type attribute of the field
335
+ # @return [Boolean] Whether it exists
287
336
  #
288
- def has_field?(locator, options={})
289
- has_selector?(:field, locator, options)
337
+ def has_field?(locator=nil, options={}, &optional_filter_block)
338
+ locator, options = nil, locator if locator.is_a? Hash
339
+ has_selector?(:field, locator, options, &optional_filter_block)
290
340
  end
291
341
 
292
342
  ##
@@ -294,13 +344,14 @@ module Capybara
294
344
  # Checks if the page or current node has no form field with the given
295
345
  # label, name or id. See {Capybara::Node::Matchers#has_field?}.
296
346
  #
297
- # @param [String] locator The label, name or id of a field to check for
298
- # @option options [String] :with The text content of the field
299
- # @option options [String] :type The type attribute of the field
300
- # @return [Boolean] Whether it doesn't exist
347
+ # @param [String] locator The label, name or id of a field to check for
348
+ # @option options [String, Regexp] :with The text content of the field or a Regexp to match
349
+ # @option options [String] :type The type attribute of the field
350
+ # @return [Boolean] Whether it doesn't exist
301
351
  #
302
- def has_no_field?(locator, options={})
303
- has_no_selector?(:field, locator, options)
352
+ def has_no_field?(locator=nil, options={}, &optional_filter_block)
353
+ locator, options = nil, locator if locator.is_a? Hash
354
+ has_no_selector?(:field, locator, options, &optional_filter_block)
304
355
  end
305
356
 
306
357
  ##
@@ -312,8 +363,9 @@ module Capybara
312
363
  # @param [String] locator The label, name or id of a checked field
313
364
  # @return [Boolean] Whether it exists
314
365
  #
315
- def has_checked_field?(locator, options={})
316
- has_selector?(:field, locator, options.merge(:checked => true))
366
+ def has_checked_field?(locator=nil, options={}, &optional_filter_block)
367
+ locator, options = nil, locator if locator.is_a? Hash
368
+ has_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
317
369
  end
318
370
 
319
371
  ##
@@ -325,8 +377,9 @@ module Capybara
325
377
  # @param [String] locator The label, name or id of a checked field
326
378
  # @return [Boolean] Whether it doesn't exist
327
379
  #
328
- def has_no_checked_field?(locator, options={})
329
- has_no_selector?(:field, locator, options.merge(:checked => true))
380
+ def has_no_checked_field?(locator=nil, options={}, &optional_filter_block)
381
+ locator, options = nil, locator if locator.is_a? Hash
382
+ has_no_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
330
383
  end
331
384
 
332
385
  ##
@@ -338,8 +391,9 @@ module Capybara
338
391
  # @param [String] locator The label, name or id of an unchecked field
339
392
  # @return [Boolean] Whether it exists
340
393
  #
341
- def has_unchecked_field?(locator, options={})
342
- has_selector?(:field, locator, options.merge(:unchecked => true))
394
+ def has_unchecked_field?(locator=nil, options={}, &optional_filter_block)
395
+ locator, options = nil, locator if locator.is_a? Hash
396
+ has_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
343
397
  end
344
398
 
345
399
  ##
@@ -351,8 +405,9 @@ module Capybara
351
405
  # @param [String] locator The label, name or id of an unchecked field
352
406
  # @return [Boolean] Whether it doesn't exist
353
407
  #
354
- def has_no_unchecked_field?(locator, options={})
355
- has_no_selector?(:field, locator, options.merge(:unchecked => true))
408
+ def has_no_unchecked_field?(locator=nil, options={}, &optional_filter_block)
409
+ locator, options = nil, locator if locator.is_a? Hash
410
+ has_no_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
356
411
  end
357
412
 
358
413
  ##
@@ -362,29 +417,31 @@ module Capybara
362
417
  #
363
418
  # It can be specified which option should currently be selected:
364
419
  #
365
- # page.has_select?('Language', :selected => 'German')
420
+ # page.has_select?('Language', selected: 'German')
366
421
  #
367
422
  # For multiple select boxes, several options may be specified:
368
423
  #
369
- # page.has_select?('Language', :selected => ['English', 'German'])
424
+ # page.has_select?('Language', selected: ['English', 'German'])
370
425
  #
371
426
  # It's also possible to check if the exact set of options exists for
372
427
  # this select box:
373
428
  #
374
- # page.has_select?('Language', :options => ['English', 'German', 'Spanish'])
429
+ # page.has_select?('Language', options: ['English', 'German', 'Spanish'])
375
430
  #
376
431
  # You can also check for a partial set of options:
377
432
  #
378
- # page.has_select?('Language', :with_options => ['English', 'German'])
433
+ # page.has_select?('Language', with_options: ['English', 'German'])
379
434
  #
380
- # @param [String] locator The label, name or id of a select box
381
- # @option options [Array] :options Options which should be contained in this select box
382
- # @option options [Array] :with_options Partial set of options which should be contained in this select box
383
- # @option options [String, Array] :selected Options which should be selected
384
- # @return [Boolean] Whether it exists
435
+ # @param [String] locator The label, name or id of a select box
436
+ # @option options [Array] :options Options which should be contained in this select box
437
+ # @option options [Array] :with_options Partial set of options which should be contained in this select box
438
+ # @option options [String, Array] :selected Options which should be selected
439
+ # @option options [String, Array] :with_selected Partial set of options which should minimally be selected
440
+ # @return [Boolean] Whether it exists
385
441
  #
386
- def has_select?(locator, options={})
387
- has_selector?(:select, locator, options)
442
+ def has_select?(locator=nil, options={}, &optional_filter_block)
443
+ locator, options = nil, locator if locator.is_a? Hash
444
+ has_selector?(:select, locator, options, &optional_filter_block)
388
445
  end
389
446
 
390
447
  ##
@@ -395,8 +452,9 @@ module Capybara
395
452
  # @param (see Capybara::Node::Matchers#has_select?)
396
453
  # @return [Boolean] Whether it doesn't exist
397
454
  #
398
- def has_no_select?(locator, options={})
399
- has_no_selector?(:select, locator, options)
455
+ def has_no_select?(locator=nil, options={}, &optional_filter_block)
456
+ locator, options = nil, locator if locator.is_a? Hash
457
+ has_no_selector?(:select, locator, options, &optional_filter_block)
400
458
  end
401
459
 
402
460
  ##
@@ -409,8 +467,9 @@ module Capybara
409
467
  # @param [String] locator The id or caption of a table
410
468
  # @return [Boolean] Whether it exist
411
469
  #
412
- def has_table?(locator, options={})
413
- has_selector?(:table, locator, options)
470
+ def has_table?(locator=nil, options={}, &optional_filter_block)
471
+ locator, options = nil, locator if locator.is_a? Hash
472
+ has_selector?(:table, locator, options, &optional_filter_block)
414
473
  end
415
474
 
416
475
  ##
@@ -421,23 +480,126 @@ module Capybara
421
480
  # @param (see Capybara::Node::Matchers#has_table?)
422
481
  # @return [Boolean] Whether it doesn't exist
423
482
  #
424
- def has_no_table?(locator, options={})
425
- has_no_selector?(:table, locator, options)
483
+ def has_no_table?(locator=nil, options={}, &optional_filter_block)
484
+ locator, options = nil, locator if locator.is_a? Hash
485
+ has_no_selector?(:table, locator, options, &optional_filter_block)
486
+ end
487
+
488
+ ##
489
+ #
490
+ # Asserts that the current_node matches a given selector
491
+ #
492
+ # node.assert_matches_selector('p#foo')
493
+ # node.assert_matches_selector(:xpath, '//p[@id="foo"]')
494
+ # node.assert_matches_selector(:foo)
495
+ #
496
+ # It also accepts all options that {Capybara::Node::Finders#all} accepts,
497
+ # such as :text and :visible.
498
+ #
499
+ # node.assert_matches_selector('li', text: 'Horse', visible: true)
500
+ #
501
+ # @param (see Capybara::Node::Finders#all)
502
+ # @raise [Capybara::ExpectationNotMet] If the selector does not match
503
+ #
504
+ def assert_matches_selector(*args, &optional_filter_block)
505
+ _verify_match_result(args, optional_filter_block) do |result|
506
+ raise Capybara::ExpectationNotMet, "Item does not match the provided selector" unless result.include? self
507
+ end
508
+ end
509
+
510
+ def assert_not_matches_selector(*args, &optional_filter_block)
511
+ _verify_match_result(args, optional_filter_block) do |result|
512
+ raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
513
+ end
514
+ end
515
+ alias_method :refute_matches_selector, :assert_not_matches_selector
516
+
517
+ ##
518
+ #
519
+ # Checks if the current node matches given selector
520
+ #
521
+ # @param (see Capybara::Node::Finders#has_selector?)
522
+ # @return [Boolean]
523
+ #
524
+ def matches_selector?(*args, &optional_filter_block)
525
+ assert_matches_selector(*args, &optional_filter_block)
526
+ rescue Capybara::ExpectationNotMet
527
+ return false
528
+ end
529
+
530
+ ##
531
+ #
532
+ # Checks if the current node matches given XPath expression
533
+ #
534
+ # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
535
+ # @return [Boolean]
536
+ #
537
+ def matches_xpath?(xpath, options={}, &optional_filter_block)
538
+ matches_selector?(:xpath, xpath, options, &optional_filter_block)
539
+ end
540
+
541
+ ##
542
+ #
543
+ # Checks if the current node matches given CSS selector
544
+ #
545
+ # @param [String] css The CSS selector to match against the current code
546
+ # @return [Boolean]
547
+ #
548
+ def matches_css?(css, options={}, &optional_filter_block)
549
+ matches_selector?(:css, css, options, &optional_filter_block)
426
550
  end
427
551
 
552
+ ##
553
+ #
554
+ # Checks if the current node does not match given selector
555
+ # Usage is identical to Capybara::Node::Matchers#has_selector?
556
+ #
557
+ # @param (see Capybara::Node::Finders#has_selector?)
558
+ # @return [Boolean]
559
+ #
560
+ def not_matches_selector?(*args, &optional_filter_block)
561
+ assert_not_matches_selector(*args, &optional_filter_block)
562
+ rescue Capybara::ExpectationNotMet
563
+ return false
564
+ end
565
+
566
+ ##
567
+ #
568
+ # Checks if the current node does not match given XPath expression
569
+ #
570
+ # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
571
+ # @return [Boolean]
572
+ #
573
+ def not_matches_xpath?(xpath, options={}, &optional_filter_block)
574
+ not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
575
+ end
576
+
577
+ ##
578
+ #
579
+ # Checks if the current node does not match given CSS selector
580
+ #
581
+ # @param [String] css The CSS selector to match against the current code
582
+ # @return [Boolean]
583
+ #
584
+ def not_matches_css?(css, options={}, &optional_filter_block)
585
+ not_matches_selector?(:css, css, options, &optional_filter_block)
586
+ end
587
+
588
+
428
589
  ##
429
590
  # Asserts that the page or current node has the given text content,
430
591
  # ignoring any HTML tags.
431
592
  #
432
593
  # @!macro text_query_params
433
594
  # @overload $0(type, text, options = {})
434
- # @param [:all, :visible] type Whether to check for only visible or all text
595
+ # @param [:all, :visible] type Whether to check for only visible or all text. If this parameter is missing or nil then we use the value of `Capybara.ignore_hidden_elements`, which defaults to `true`, corresponding to `:visible`.
435
596
  # @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
436
597
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
437
598
  # @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
438
599
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
439
600
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
440
601
  # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
602
+ # @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
441
603
  # @overload $0(text, options = {})
442
604
  # @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
443
605
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
@@ -445,19 +607,16 @@ module Capybara
445
607
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
446
608
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
447
609
  # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
610
+ # @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
448
611
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
449
612
  # @return [true]
450
613
  #
451
614
  def assert_text(*args)
452
- query = Capybara::Queries::TextQuery.new(*args)
453
- synchronize(query.wait) do
454
- count = query.resolve_for(self)
455
- matches_count = Capybara::Helpers.matches_count?(count, query.options)
456
- unless matches_count && ((count > 0) || Capybara::Helpers.expects_none?(query.options))
615
+ _verify_text(args) do |count, query|
616
+ unless query.matches_count?(count) && ((count > 0) || query.expects_none?)
457
617
  raise Capybara::ExpectationNotMet, query.failure_message
458
618
  end
459
619
  end
460
- return true
461
620
  end
462
621
 
463
622
  ##
@@ -469,15 +628,11 @@ module Capybara
469
628
  # @return [true]
470
629
  #
471
630
  def assert_no_text(*args)
472
- query = Capybara::Queries::TextQuery.new(*args)
473
- synchronize(query.wait) do
474
- count = query.resolve_for(self)
475
- matches_count = Capybara::Helpers.matches_count?(count, query.options)
476
- if matches_count && ((count > 0) || Capybara::Helpers.expects_none?(query.options))
631
+ _verify_text(args) do |count, query|
632
+ if query.matches_count?(count) && ((count > 0) || query.expects_none?)
477
633
  raise Capybara::ExpectationNotMet, query.negative_failure_message
478
634
  end
479
635
  end
480
- return true
481
636
  end
482
637
 
483
638
  ##
@@ -522,6 +677,47 @@ module Capybara
522
677
  def ==(other)
523
678
  self.eql?(other) || (other.respond_to?(:base) && base == other.base)
524
679
  end
680
+
681
+ private
682
+
683
+ def _verify_selector_result(query_args, optional_filter_block, &result_block)
684
+ _set_query_session_options(query_args)
685
+ query = Capybara::Queries::SelectorQuery.new(*query_args, &optional_filter_block)
686
+ synchronize(query.wait) do
687
+ result = query.resolve_for(self)
688
+ result_block.call(result, query)
689
+ end
690
+ return true
691
+ end
692
+
693
+ def _verify_match_result(query_args, optional_filter_block, &result_block)
694
+ _set_query_session_options(query_args)
695
+ query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
696
+ synchronize(query.wait) do
697
+ result = query.resolve_for(self.query_scope)
698
+ result_block.call(result)
699
+ end
700
+ return true
701
+ end
702
+
703
+ def _verify_text(query_args)
704
+ _set_query_session_options(query_args)
705
+ query = Capybara::Queries::TextQuery.new(*query_args)
706
+ synchronize(query.wait) do
707
+ count = query.resolve_for(self)
708
+ yield(count, query)
709
+ end
710
+ return true
711
+ end
712
+
713
+ def _set_query_session_options(query_args)
714
+ if query_args.last.is_a? Hash
715
+ query_args.last[:session_options] = session_options
716
+ else
717
+ query_args.push(session_options: session_options)
718
+ end
719
+ query_args
720
+ end
525
721
  end
526
722
  end
527
723
  end