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
@@ -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