capybara 2.6.2 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +40 -15
  3. data/README.md +45 -38
  4. data/lib/capybara.rb +86 -10
  5. data/lib/capybara/cucumber.rb +1 -0
  6. data/lib/capybara/driver/base.rb +5 -2
  7. data/lib/capybara/driver/node.rb +1 -0
  8. data/lib/capybara/dsl.rb +1 -0
  9. data/lib/capybara/helpers.rb +3 -2
  10. data/lib/capybara/node/actions.rb +6 -0
  11. data/lib/capybara/node/base.rb +1 -0
  12. data/lib/capybara/node/document.rb +1 -0
  13. data/lib/capybara/node/document_matchers.rb +1 -0
  14. data/lib/capybara/node/element.rb +1 -0
  15. data/lib/capybara/node/finders.rb +3 -2
  16. data/lib/capybara/node/matchers.rb +72 -2
  17. data/lib/capybara/node/simple.rb +6 -3
  18. data/lib/capybara/queries/base_query.rb +1 -0
  19. data/lib/capybara/queries/current_path_query.rb +1 -0
  20. data/lib/capybara/queries/match_query.rb +21 -0
  21. data/lib/capybara/queries/selector_query.rb +138 -0
  22. data/lib/capybara/queries/text_query.rb +1 -0
  23. data/lib/capybara/queries/title_query.rb +1 -0
  24. data/lib/capybara/query.rb +3 -131
  25. data/lib/capybara/rack_test/browser.rb +1 -0
  26. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  27. data/lib/capybara/rack_test/driver.rb +6 -4
  28. data/lib/capybara/rack_test/form.rb +1 -0
  29. data/lib/capybara/rack_test/node.rb +1 -0
  30. data/lib/capybara/rails.rb +2 -1
  31. data/lib/capybara/result.rb +1 -0
  32. data/lib/capybara/rspec.rb +1 -0
  33. data/lib/capybara/rspec/features.rb +1 -0
  34. data/lib/capybara/rspec/matchers.rb +54 -3
  35. data/lib/capybara/selector.rb +175 -75
  36. data/lib/capybara/selector/filter.rb +48 -0
  37. data/lib/capybara/selenium/driver.rb +24 -7
  38. data/lib/capybara/selenium/node.rb +1 -0
  39. data/lib/capybara/server.rb +38 -6
  40. data/lib/capybara/session.rb +30 -14
  41. data/lib/capybara/session/matchers.rb +2 -1
  42. data/lib/capybara/spec/public/test.js +6 -0
  43. data/lib/capybara/spec/session/accept_alert_spec.rb +2 -1
  44. data/lib/capybara/spec/session/accept_confirm_spec.rb +2 -1
  45. data/lib/capybara/spec/session/accept_prompt_spec.rb +2 -1
  46. data/lib/capybara/spec/session/all_spec.rb +1 -0
  47. data/lib/capybara/spec/session/assert_current_path.rb +1 -0
  48. data/lib/capybara/spec/session/assert_selector.rb +1 -0
  49. data/lib/capybara/spec/session/assert_text.rb +1 -0
  50. data/lib/capybara/spec/session/assert_title.rb +1 -0
  51. data/lib/capybara/spec/session/attach_file_spec.rb +1 -0
  52. data/lib/capybara/spec/session/body_spec.rb +1 -0
  53. data/lib/capybara/spec/session/check_spec.rb +1 -0
  54. data/lib/capybara/spec/session/choose_spec.rb +1 -0
  55. data/lib/capybara/spec/session/click_button_spec.rb +1 -0
  56. data/lib/capybara/spec/session/click_link_or_button_spec.rb +1 -0
  57. data/lib/capybara/spec/session/click_link_spec.rb +1 -0
  58. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  59. data/lib/capybara/spec/session/current_url_spec.rb +1 -0
  60. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +2 -1
  61. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -1
  62. data/lib/capybara/spec/session/element/assert_match_selector.rb +31 -0
  63. data/lib/capybara/spec/session/element/match_css_spec.rb +17 -0
  64. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  65. data/lib/capybara/spec/session/element/matches_selector_spec.rb +63 -0
  66. data/lib/capybara/spec/session/evaluate_script_spec.rb +1 -0
  67. data/lib/capybara/spec/session/execute_script_spec.rb +1 -0
  68. data/lib/capybara/spec/session/fill_in_spec.rb +1 -0
  69. data/lib/capybara/spec/session/find_button_spec.rb +1 -0
  70. data/lib/capybara/spec/session/find_by_id_spec.rb +1 -0
  71. data/lib/capybara/spec/session/find_field_spec.rb +1 -0
  72. data/lib/capybara/spec/session/find_link_spec.rb +1 -0
  73. data/lib/capybara/spec/session/find_spec.rb +1 -0
  74. data/lib/capybara/spec/session/first_spec.rb +1 -0
  75. data/lib/capybara/spec/session/go_back_spec.rb +1 -0
  76. data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
  77. data/lib/capybara/spec/session/has_button_spec.rb +1 -0
  78. data/lib/capybara/spec/session/has_css_spec.rb +1 -0
  79. data/lib/capybara/spec/session/has_current_path_spec.rb +1 -0
  80. data/lib/capybara/spec/session/has_field_spec.rb +13 -0
  81. data/lib/capybara/spec/session/has_link_spec.rb +1 -0
  82. data/lib/capybara/spec/session/has_select_spec.rb +19 -0
  83. data/lib/capybara/spec/session/has_selector_spec.rb +6 -0
  84. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  85. data/lib/capybara/spec/session/has_text_spec.rb +1 -0
  86. data/lib/capybara/spec/session/has_title_spec.rb +1 -0
  87. data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
  88. data/lib/capybara/spec/session/headers.rb +1 -0
  89. data/lib/capybara/spec/session/html_spec.rb +1 -0
  90. data/lib/capybara/spec/session/node_spec.rb +29 -0
  91. data/lib/capybara/spec/session/reset_session_spec.rb +35 -1
  92. data/lib/capybara/spec/session/response_code.rb +1 -0
  93. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  94. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +3 -2
  95. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  96. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  97. data/lib/capybara/spec/session/screenshot_spec.rb +3 -1
  98. data/lib/capybara/spec/session/select_spec.rb +1 -0
  99. data/lib/capybara/spec/session/selectors_spec.rb +35 -0
  100. data/lib/capybara/spec/session/text_spec.rb +1 -0
  101. data/lib/capybara/spec/session/title_spec.rb +2 -1
  102. data/lib/capybara/spec/session/uncheck_spec.rb +1 -0
  103. data/lib/capybara/spec/session/unselect_spec.rb +1 -0
  104. data/lib/capybara/spec/session/visit_spec.rb +1 -0
  105. data/lib/capybara/spec/session/window/become_closed_spec.rb +1 -0
  106. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  107. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  108. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -0
  109. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -0
  110. data/lib/capybara/spec/session/window/window_spec.rb +1 -8
  111. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  112. data/lib/capybara/spec/session/window/within_window_spec.rb +2 -3
  113. data/lib/capybara/spec/session/within_frame_spec.rb +1 -0
  114. data/lib/capybara/spec/session/within_spec.rb +1 -0
  115. data/lib/capybara/spec/spec_helper.rb +2 -0
  116. data/lib/capybara/spec/test_app.rb +1 -0
  117. data/lib/capybara/spec/views/buttons.erb +1 -0
  118. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  119. data/lib/capybara/spec/views/form.erb +24 -0
  120. data/lib/capybara/spec/views/frame_child.erb +2 -1
  121. data/lib/capybara/spec/views/frame_one.erb +2 -1
  122. data/lib/capybara/spec/views/frame_parent.erb +2 -1
  123. data/lib/capybara/spec/views/frame_two.erb +2 -1
  124. data/lib/capybara/spec/views/header_links.erb +1 -0
  125. data/lib/capybara/spec/views/host_links.erb +1 -0
  126. data/lib/capybara/spec/views/path.erb +1 -0
  127. data/lib/capybara/spec/views/popup_one.erb +1 -0
  128. data/lib/capybara/spec/views/popup_two.erb +1 -0
  129. data/lib/capybara/spec/views/postback.erb +2 -1
  130. data/lib/capybara/spec/views/tables.erb +1 -0
  131. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  132. data/lib/capybara/spec/views/with_count.erb +2 -1
  133. data/lib/capybara/spec/views/with_hover.erb +2 -1
  134. data/lib/capybara/spec/views/with_html.erb +3 -0
  135. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  136. data/lib/capybara/spec/views/with_js.erb +5 -0
  137. data/lib/capybara/spec/views/with_scope.erb +1 -0
  138. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  139. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  140. data/lib/capybara/spec/views/with_title.erb +2 -1
  141. data/lib/capybara/spec/views/with_unload_alert.erb +12 -0
  142. data/lib/capybara/spec/views/with_windows.erb +1 -0
  143. data/lib/capybara/spec/views/within_frames.erb +2 -1
  144. data/lib/capybara/version.rb +2 -1
  145. data/lib/capybara/window.rb +1 -0
  146. data/spec/basic_node_spec.rb +1 -0
  147. data/spec/capybara_spec.rb +28 -1
  148. data/spec/dsl_spec.rb +1 -0
  149. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -0
  150. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -0
  151. data/spec/rack_test_spec.rb +1 -0
  152. data/spec/result_spec.rb +1 -0
  153. data/spec/rspec/features_spec.rb +1 -0
  154. data/spec/rspec/matchers_spec.rb +1 -0
  155. data/spec/rspec/scenarios_spec.rb +1 -0
  156. data/spec/rspec/views_spec.rb +1 -0
  157. data/spec/rspec_spec.rb +1 -0
  158. data/spec/selector_spec.rb +55 -1
  159. data/spec/selenium_spec.rb +6 -2
  160. data/spec/selenium_spec_chrome.rb +1 -0
  161. data/spec/server_spec.rb +101 -13
  162. data/spec/spec_helper.rb +1 -0
  163. metadata +16 -6
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'capybara/dsl'
2
3
  require 'capybara/rspec/matchers'
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class Capybara::Driver::Base
2
3
  def current_url
3
4
  raise NotImplementedError
@@ -90,8 +91,8 @@ class Capybara::Driver::Base
90
91
  def no_such_window_error
91
92
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#no_such_window_error'
92
93
  end
93
-
94
-
94
+
95
+
95
96
  ##
96
97
  #
97
98
  # Execute the block, and then accept the modal opened.
@@ -134,7 +135,9 @@ class Capybara::Driver::Base
134
135
  false
135
136
  end
136
137
 
138
+ # @deprecated This method is being removed
137
139
  def browser_initialized?
140
+ warn "DEPRECATED: #browser_initialized? is deprecated and will be removed in the next version of Capybara"
138
141
  true
139
142
  end
140
143
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Driver
3
4
  class Node
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'capybara'
2
3
 
3
4
  module Capybara
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Capybara
4
5
 
@@ -96,7 +97,7 @@ module Capybara
96
97
  # @option [Integer] minimum Count should have been larger than or equal to this value
97
98
  #
98
99
  def failure_message(description, options={})
99
- message = "expected to find #{description}"
100
+ message = String.new("expected to find #{description}")
100
101
  if options[:count]
101
102
  message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
102
103
  elsif options[:between]
@@ -129,7 +130,7 @@ module Capybara
129
130
 
130
131
  if defined?(Process::CLOCK_MONOTONIC)
131
132
  def monotonic_time
132
- Process.clock_gettime Process::CLOCK_MONOTONIC
133
+ Process.clock_gettime Process::CLOCK_MONOTONIC
133
134
  end
134
135
  else
135
136
  def monotonic_time
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module Actions
@@ -150,6 +151,11 @@ module Capybara
150
151
  # @param [String] locator Which field to attach the file to
151
152
  # @param [String] path The path of the file that will be attached, or an array of paths
152
153
  #
154
+ # @option options [Symbol] match (Capybara.match) The matching strategy to use (:one, :first, :prefer_exact, :smart).
155
+ # @option options [Boolean] exact (Capybara.exact) Match the exact label name/contents or accept a partial match.
156
+ # @option options [Fixnum] wait (Capybara.default_max_wait_time) If using a Javascript driver, maximum number of seconds during which the element will be searched for.
157
+ # @option options [Boolean] multiple Match field which allows multiple file selection
158
+ #
153
159
  def attach_file(locator, path, options={})
154
160
  Array(path).each do |p|
155
161
  raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module DocumentMatchers
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module Finders
@@ -28,7 +29,7 @@ module Capybara
28
29
  # @raise [Capybara::ElementNotFound] If the element can't be found before time expires
29
30
  #
30
31
  def find(*args)
31
- query = Capybara::Query.new(*args)
32
+ query = Capybara::Queries::SelectorQuery.new(*args)
32
33
  synchronize(query.wait) do
33
34
  if query.match == :smart or query.match == :prefer_exact
34
35
  result = query.resolve_for(self, true)
@@ -177,7 +178,7 @@ module Capybara
177
178
  # @return [Capybara::Result] A collection of found elements
178
179
  #
179
180
  def all(*args)
180
- query = Capybara::Query.new(*args)
181
+ query = Capybara::Queries::SelectorQuery.new(*args)
181
182
  synchronize(query.wait) do
182
183
  result = query.resolve_for(self)
183
184
  raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
  module Matchers
@@ -55,6 +56,36 @@ module Capybara
55
56
  return false
56
57
  end
57
58
 
59
+ ##
60
+ #
61
+ # Checks if the current node matches given selector
62
+ # Usage is identical to Capybara::Node::Matchers#has_selector?
63
+ #
64
+ # @param (see Capybara::Node::Finders#has_selector?)
65
+ # @return [Boolean]
66
+ #
67
+ def matches_selector?(*args)
68
+ assert_matches_selector(*args)
69
+ rescue Capybara::ExpectationNotMet
70
+ return false
71
+ end
72
+
73
+
74
+ ##
75
+ #
76
+ # Checks if the current node does not match given selector
77
+ # Usage is identical to Capybara::Node::Matchers#has_selector?
78
+ #
79
+ # @param (see Capybara::Node::Finders#has_selector?)
80
+ # @return [Boolean]
81
+ #
82
+ def not_matches_selector?(*args)
83
+ assert_not_matches_selector(*args)
84
+ rescue Capybara::ExpectationNotMet
85
+ return false
86
+ end
87
+
88
+
58
89
  ##
59
90
  #
60
91
  # Asserts that a given selector is on the page or current node.
@@ -89,7 +120,7 @@ module Capybara
89
120
  # @raise [Capybara::ExpectationNotMet] If the selector does not exist
90
121
  #
91
122
  def assert_selector(*args)
92
- query = Capybara::Query.new(*args)
123
+ query = Capybara::Queries::SelectorQuery.new(*args)
93
124
  synchronize(query.wait) do
94
125
  result = query.resolve_for(self)
95
126
  matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
@@ -117,7 +148,7 @@ module Capybara
117
148
  # @raise [Capybara::ExpectationNotMet] If the selector exists
118
149
  #
119
150
  def assert_no_selector(*args)
120
- query = Capybara::Query.new(*args)
151
+ query = Capybara::Queries::SelectorQuery.new(*args)
121
152
  synchronize(query.wait) do
122
153
  result = query.resolve_for(self)
123
154
  matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
@@ -129,6 +160,45 @@ module Capybara
129
160
  end
130
161
  alias_method :refute_selector, :assert_no_selector
131
162
 
163
+ ##
164
+ #
165
+ # Asserts that the current_node matches a given selector
166
+ #
167
+ # node.assert_matches_selector('p#foo')
168
+ # node.assert_matches_selector(:xpath, '//p[@id="foo"]')
169
+ # node.assert_matches_selector(:foo)
170
+ #
171
+ # It also accepts all options that {Capybara::Node::Finders#all} accepts,
172
+ # such as :text and :visible.
173
+ #
174
+ # node.assert_matches_selector('li', :text => 'Horse', :visible => true)
175
+ #
176
+ # @param (see Capybara::Node::Finders#all)
177
+ # @raise [Capybara::ExpectationNotMet] If the selector does not match
178
+ #
179
+ def assert_matches_selector(*args)
180
+ query = Capybara::Queries::MatchQuery.new(*args)
181
+ synchronize(query.wait) do
182
+ result = query.resolve_for(self.parent)
183
+ unless result.include? self
184
+ raise Capybara::ExpectationNotMet, "Item does not match the provided selector"
185
+ end
186
+ end
187
+ return true
188
+ end
189
+
190
+ def assert_not_matches_selector(*args)
191
+ query = Capybara::Queries::MatchQuery.new(*args)
192
+ synchronize(query.wait) do
193
+ result = query.resolve_for(self.parent)
194
+ if result.include? self
195
+ raise Capybara::ExpectationNotMet, 'Item matched the provided selector'
196
+ end
197
+ end
198
+ return true
199
+ end
200
+ alias_method :refute_matches_selector, :assert_not_matches_selector
201
+
132
202
  ##
133
203
  #
134
204
  # Checks if a given XPath expression is on the page or current node.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  module Node
3
4
 
@@ -99,6 +100,8 @@ module Capybara
99
100
  # @return [Boolean] Whether the element is visible
100
101
  #
101
102
  def visible?(check_ancestors = true)
103
+ return false if (tag_name == 'input') && (native[:type]=="hidden")
104
+
102
105
  if check_ancestors
103
106
  #check size because oldest supported nokogiri doesnt support xpath boolean() function
104
107
  native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head']").size() == 0
@@ -115,7 +118,7 @@ module Capybara
115
118
  # @return [Boolean] Whether the element is checked
116
119
  #
117
120
  def checked?
118
- native[:checked]
121
+ native.has_attribute?('checked')
119
122
  end
120
123
 
121
124
  ##
@@ -124,7 +127,7 @@ module Capybara
124
127
  #
125
128
  # @return [Boolean] Whether the element is disabled
126
129
  def disabled?
127
- native[:disabled]
130
+ native.has_attribute?('disabled')
128
131
  end
129
132
 
130
133
  ##
@@ -134,7 +137,7 @@ module Capybara
134
137
  # @return [Boolean] Whether the element is selected
135
138
  #
136
139
  def selected?
137
- native[:selected]
140
+ native.has_attribute?('selected')
138
141
  end
139
142
 
140
143
  def synchronize(seconds=nil)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Capybara
2
3
  # @api private
3
4
  module Queries
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'addressable/uri'
2
3
 
3
4
  module Capybara
@@ -0,0 +1,21 @@
1
+ module Capybara
2
+ module Queries
3
+ class MatchQuery < Capybara::Queries::SelectorQuery
4
+ VALID_KEYS = [:text, :visible, :exact, :wait]
5
+
6
+ def visible
7
+ if options.has_key?(:visible)
8
+ super
9
+ else
10
+ :all
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def valid_keys
17
+ VALID_KEYS + @selector.custom_filters.keys
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+ module Capybara
3
+ module Queries
4
+ class SelectorQuery < Queries::BaseQuery
5
+ attr_accessor :selector, :locator, :options, :expression, :find, :negative
6
+
7
+ VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait]
8
+ VALID_MATCH = [:first, :smart, :prefer_exact, :one]
9
+
10
+ def initialize(*args)
11
+ @options = if args.last.is_a?(Hash) then args.pop.dup else {} end
12
+
13
+ if args[0].is_a?(Symbol)
14
+ @selector = Selector.all[args.shift]
15
+ @locator = args.shift
16
+ else
17
+ @selector = Selector.all.values.find { |s| s.match?(args[0]) }
18
+ @locator = args.shift
19
+ end
20
+ @selector ||= Selector.all[Capybara.default_selector]
21
+
22
+ warn "Unused parameters passed to #{self.class.name} : #{args.to_s}" unless args.empty?
23
+
24
+ # for compatibility with Capybara 2.0
25
+ if Capybara.exact_options and @selector == Selector.all[:option]
26
+ @options[:exact] = true
27
+ end
28
+
29
+ @expression = @selector.call(@locator)
30
+ assert_valid_keys
31
+ end
32
+
33
+ def name; selector.name; end
34
+ def label; selector.label or selector.name; end
35
+
36
+ def description
37
+ @description = String.new("#{label} #{locator.inspect}")
38
+ @description << " with text #{options[:text].inspect}" if options[:text]
39
+ @description << selector.description(options)
40
+ @description
41
+ end
42
+
43
+ def matches_filters?(node)
44
+ if options[:text]
45
+ regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
46
+ return false if not node.text(visible).match(regexp)
47
+ end
48
+ case visible
49
+ when :visible then return false unless node.visible?
50
+ when :hidden then return false if node.visible?
51
+ end
52
+ selector.custom_filters.each do |name, filter|
53
+ if options.has_key?(name)
54
+ return false unless filter.matches?(node, options[name])
55
+ elsif filter.default?
56
+ return false unless filter.matches?(node, filter.default)
57
+ end
58
+ end
59
+ end
60
+
61
+ def visible
62
+ if options.has_key?(:visible)
63
+ case @options[:visible]
64
+ when true then :visible
65
+ when false then :all
66
+ else @options[:visible]
67
+ end
68
+ else
69
+ if Capybara.ignore_hidden_elements
70
+ :visible
71
+ else
72
+ :all
73
+ end
74
+ end
75
+ end
76
+
77
+ def exact?
78
+ if options.has_key?(:exact)
79
+ @options[:exact]
80
+ else
81
+ Capybara.exact
82
+ end
83
+ end
84
+
85
+ def match
86
+ if options.has_key?(:match)
87
+ @options[:match]
88
+ else
89
+ Capybara.match
90
+ end
91
+ end
92
+
93
+ def xpath(exact=nil)
94
+ exact = self.exact? if exact == nil
95
+ if @expression.respond_to?(:to_xpath) and exact
96
+ @expression.to_xpath(:exact)
97
+ else
98
+ @expression.to_s
99
+ end
100
+ end
101
+
102
+ def css
103
+ @expression
104
+ end
105
+
106
+ # @api private
107
+ def resolve_for(node, exact = nil)
108
+ node.synchronize do
109
+ children = if selector.format == :css
110
+ node.find_css(self.css)
111
+ else
112
+ node.find_xpath(self.xpath(exact))
113
+ end.map do |child|
114
+ if node.is_a?(Capybara::Node::Base)
115
+ Capybara::Node::Element.new(node.session, child, node, self)
116
+ else
117
+ Capybara::Node::Simple.new(child)
118
+ end
119
+ end
120
+ Capybara::Result.new(children, self)
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def valid_keys
127
+ COUNT_KEYS + [:text, :visible, :exact, :match, :wait] + @selector.custom_filters.keys
128
+ end
129
+
130
+ def assert_valid_keys
131
+ super
132
+ unless VALID_MATCH.include?(match)
133
+ raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}"
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end