capybara 1.1.4 → 2.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +100 -0
- data/License.txt +22 -0
- data/README.md +829 -0
- data/lib/capybara.rb +124 -6
- data/lib/capybara/cucumber.rb +2 -5
- data/lib/capybara/driver/base.rb +5 -5
- data/lib/capybara/driver/node.rb +2 -2
- data/lib/capybara/dsl.rb +3 -121
- data/lib/capybara/node/actions.rb +12 -28
- data/lib/capybara/node/base.rb +5 -13
- data/lib/capybara/node/element.rb +21 -21
- data/lib/capybara/node/finders.rb +27 -89
- data/lib/capybara/node/matchers.rb +107 -69
- data/lib/capybara/node/simple.rb +11 -13
- data/lib/capybara/query.rb +78 -0
- data/lib/capybara/rack_test/browser.rb +16 -27
- data/lib/capybara/rack_test/driver.rb +11 -1
- data/lib/capybara/rack_test/node.rb +17 -1
- data/lib/capybara/result.rb +84 -0
- data/lib/capybara/rspec/matchers.rb +28 -63
- data/lib/capybara/selector.rb +97 -33
- data/lib/capybara/selenium/driver.rb +14 -61
- data/lib/capybara/selenium/node.rb +6 -15
- data/lib/capybara/server.rb +32 -27
- data/lib/capybara/session.rb +54 -30
- data/lib/capybara/spec/public/jquery-ui.js +791 -0
- data/lib/capybara/spec/public/jquery.js +9046 -0
- data/lib/capybara/spec/public/test.js +4 -1
- data/lib/capybara/spec/session.rb +56 -27
- data/lib/capybara/spec/session/all_spec.rb +8 -4
- data/lib/capybara/spec/session/attach_file_spec.rb +12 -9
- data/lib/capybara/spec/session/check_spec.rb +6 -3
- data/lib/capybara/spec/session/choose_spec.rb +4 -1
- data/lib/capybara/spec/session/click_button_spec.rb +5 -14
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +2 -1
- data/lib/capybara/spec/session/click_link_spec.rb +3 -17
- data/lib/capybara/spec/session/current_url_spec.rb +77 -9
- data/lib/capybara/spec/session/fill_in_spec.rb +8 -18
- data/lib/capybara/spec/session/find_spec.rb +19 -46
- data/lib/capybara/spec/session/first_spec.rb +2 -34
- data/lib/capybara/spec/session/has_css_spec.rb +1 -1
- data/lib/capybara/spec/session/has_field_spec.rb +28 -0
- data/lib/capybara/spec/session/has_select_spec.rb +84 -31
- data/lib/capybara/spec/session/has_table_spec.rb +7 -69
- data/lib/capybara/spec/session/has_text_spec.rb +168 -0
- data/lib/capybara/spec/session/javascript.rb +65 -81
- data/lib/capybara/spec/session/node_spec.rb +115 -0
- data/lib/capybara/spec/session/screenshot.rb +29 -0
- data/lib/capybara/spec/session/select_spec.rb +12 -12
- data/lib/capybara/spec/session/text_spec.rb +9 -4
- data/lib/capybara/spec/session/unselect_spec.rb +12 -6
- data/lib/capybara/spec/session/visit_spec.rb +76 -0
- data/lib/capybara/spec/session/within_frame_spec.rb +33 -0
- data/lib/capybara/spec/session/within_spec.rb +47 -58
- data/lib/capybara/spec/session/within_window_spec.rb +40 -0
- data/lib/capybara/spec/test_app.rb +27 -3
- data/lib/capybara/spec/views/form.erb +11 -10
- data/lib/capybara/spec/views/host_links.erb +2 -2
- data/lib/capybara/spec/views/tables.erb +6 -66
- data/lib/capybara/spec/views/with_html.erb +3 -3
- data/lib/capybara/spec/views/with_js.erb +11 -8
- data/lib/capybara/util/save_and_open_page.rb +4 -3
- data/lib/capybara/version.rb +1 -1
- data/spec/basic_node_spec.rb +15 -3
- data/spec/dsl_spec.rb +12 -10
- data/spec/rack_test_spec.rb +152 -0
- data/spec/rspec/features_spec.rb +0 -2
- data/spec/rspec/matchers_spec.rb +164 -89
- data/spec/rspec_spec.rb +0 -2
- data/spec/selenium_spec.rb +67 -0
- data/spec/server_spec.rb +35 -23
- data/spec/spec_helper.rb +18 -2
- metadata +30 -30
- data/README.rdoc +0 -722
- data/lib/capybara/spec/driver.rb +0 -301
- data/lib/capybara/spec/session/current_host_spec.rb +0 -68
- data/lib/capybara/spec/session/has_content_spec.rb +0 -106
- data/lib/capybara/util/timeout.rb +0 -27
- data/spec/driver/rack_test_driver_spec.rb +0 -89
- data/spec/driver/selenium_driver_spec.rb +0 -37
- data/spec/session/rack_test_session_spec.rb +0 -55
- data/spec/session/selenium_session_spec.rb +0 -26
- data/spec/string_spec.rb +0 -77
- data/spec/timeout_spec.rb +0 -28
data/lib/capybara/node/base.rb
CHANGED
@@ -33,29 +33,19 @@ module Capybara
|
|
33
33
|
@base = base
|
34
34
|
end
|
35
35
|
|
36
|
+
# overridden in subclasses, e.g. Capybara::Node::Element
|
36
37
|
def reload
|
37
38
|
self
|
38
39
|
end
|
39
40
|
|
40
|
-
def
|
41
|
-
orig = @wait_disabled
|
42
|
-
@wait_disabled = true
|
43
|
-
yield
|
44
|
-
ensure
|
45
|
-
@wait_disabled = orig
|
46
|
-
end
|
47
|
-
|
48
|
-
protected
|
49
|
-
|
50
|
-
def wait_until(seconds=Capybara.default_wait_time)
|
41
|
+
def synchronize(seconds=Capybara.default_wait_time)
|
51
42
|
start_time = Time.now
|
52
43
|
|
53
44
|
begin
|
54
45
|
yield
|
55
46
|
rescue => e
|
56
|
-
raise e if @wait_disabled
|
57
47
|
raise e unless driver.wait?
|
58
|
-
raise e unless
|
48
|
+
raise e unless driver.invalid_element_errors.include?(e.class) or e.is_a?(Capybara::ElementNotFound)
|
59
49
|
raise e if (Time.now - start_time) >= seconds
|
60
50
|
sleep(0.05)
|
61
51
|
raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == start_time
|
@@ -64,6 +54,8 @@ module Capybara
|
|
64
54
|
end
|
65
55
|
end
|
66
56
|
|
57
|
+
protected
|
58
|
+
|
67
59
|
def driver
|
68
60
|
session.driver
|
69
61
|
end
|
@@ -22,10 +22,10 @@ module Capybara
|
|
22
22
|
#
|
23
23
|
class Element < Base
|
24
24
|
|
25
|
-
def initialize(session, base, parent,
|
25
|
+
def initialize(session, base, parent, query)
|
26
26
|
super(session, base)
|
27
27
|
@parent = parent
|
28
|
-
@
|
28
|
+
@query = query
|
29
29
|
end
|
30
30
|
|
31
31
|
def allow_reload!
|
@@ -37,7 +37,7 @@ module Capybara
|
|
37
37
|
# @return [Object] The native element from the driver, this allows access to driver specific methods
|
38
38
|
#
|
39
39
|
def native
|
40
|
-
|
40
|
+
synchronize { base.native }
|
41
41
|
end
|
42
42
|
|
43
43
|
##
|
@@ -45,7 +45,7 @@ module Capybara
|
|
45
45
|
# @return [String] The text of the element
|
46
46
|
#
|
47
47
|
def text
|
48
|
-
|
48
|
+
synchronize { base.text }
|
49
49
|
end
|
50
50
|
|
51
51
|
##
|
@@ -58,7 +58,7 @@ module Capybara
|
|
58
58
|
# @return [String] The value of the attribute
|
59
59
|
#
|
60
60
|
def [](attribute)
|
61
|
-
|
61
|
+
synchronize { base[attribute] }
|
62
62
|
end
|
63
63
|
|
64
64
|
##
|
@@ -66,7 +66,7 @@ module Capybara
|
|
66
66
|
# @return [String] The value of the form element
|
67
67
|
#
|
68
68
|
def value
|
69
|
-
|
69
|
+
synchronize { base.value }
|
70
70
|
end
|
71
71
|
|
72
72
|
##
|
@@ -76,7 +76,7 @@ module Capybara
|
|
76
76
|
# @param [String] value The new value
|
77
77
|
#
|
78
78
|
def set(value)
|
79
|
-
|
79
|
+
synchronize { base.set(value) }
|
80
80
|
end
|
81
81
|
|
82
82
|
##
|
@@ -84,7 +84,7 @@ module Capybara
|
|
84
84
|
# Select this node if is an option element inside a select tag
|
85
85
|
#
|
86
86
|
def select_option
|
87
|
-
|
87
|
+
synchronize { base.select_option }
|
88
88
|
end
|
89
89
|
|
90
90
|
##
|
@@ -92,7 +92,7 @@ module Capybara
|
|
92
92
|
# Unselect this node if is an option element inside a multiple select tag
|
93
93
|
#
|
94
94
|
def unselect_option
|
95
|
-
|
95
|
+
synchronize { base.unselect_option }
|
96
96
|
end
|
97
97
|
|
98
98
|
##
|
@@ -100,7 +100,7 @@ module Capybara
|
|
100
100
|
# Click the Element
|
101
101
|
#
|
102
102
|
def click
|
103
|
-
|
103
|
+
synchronize { base.click }
|
104
104
|
end
|
105
105
|
|
106
106
|
##
|
@@ -108,7 +108,7 @@ module Capybara
|
|
108
108
|
# @return [String] The tag name of the element
|
109
109
|
#
|
110
110
|
def tag_name
|
111
|
-
|
111
|
+
synchronize { base.tag_name }
|
112
112
|
end
|
113
113
|
|
114
114
|
##
|
@@ -119,7 +119,7 @@ module Capybara
|
|
119
119
|
# @return [Boolean] Whether the element is visible
|
120
120
|
#
|
121
121
|
def visible?
|
122
|
-
|
122
|
+
synchronize { base.visible? }
|
123
123
|
end
|
124
124
|
|
125
125
|
##
|
@@ -129,7 +129,7 @@ module Capybara
|
|
129
129
|
# @return [Boolean] Whether the element is checked
|
130
130
|
#
|
131
131
|
def checked?
|
132
|
-
|
132
|
+
synchronize { base.checked? }
|
133
133
|
end
|
134
134
|
|
135
135
|
##
|
@@ -139,7 +139,7 @@ module Capybara
|
|
139
139
|
# @return [Boolean] Whether the element is selected
|
140
140
|
#
|
141
141
|
def selected?
|
142
|
-
|
142
|
+
synchronize { base.selected? }
|
143
143
|
end
|
144
144
|
|
145
145
|
##
|
@@ -149,7 +149,7 @@ module Capybara
|
|
149
149
|
# @return [String] An XPath expression
|
150
150
|
#
|
151
151
|
def path
|
152
|
-
|
152
|
+
synchronize { base.path }
|
153
153
|
end
|
154
154
|
|
155
155
|
##
|
@@ -160,7 +160,7 @@ module Capybara
|
|
160
160
|
# @param [String] event The name of the event to trigger
|
161
161
|
#
|
162
162
|
def trigger(event)
|
163
|
-
|
163
|
+
synchronize { base.trigger(event) }
|
164
164
|
end
|
165
165
|
|
166
166
|
##
|
@@ -174,24 +174,24 @@ module Capybara
|
|
174
174
|
# @param [Capybara::Element] node The element to drag to
|
175
175
|
#
|
176
176
|
def drag_to(node)
|
177
|
-
|
177
|
+
synchronize { base.drag_to(node.base) }
|
178
178
|
end
|
179
179
|
|
180
180
|
def find(*args)
|
181
|
-
|
181
|
+
synchronize { super }
|
182
182
|
end
|
183
183
|
|
184
184
|
def first(*args)
|
185
|
-
|
185
|
+
synchronize { super }
|
186
186
|
end
|
187
187
|
|
188
188
|
def all(*args)
|
189
|
-
|
189
|
+
synchronize { super }
|
190
190
|
end
|
191
191
|
|
192
192
|
def reload
|
193
193
|
if @allow_reload
|
194
|
-
reloaded = parent.reload.first(@
|
194
|
+
reloaded = parent.reload.first(@query.name, @query.locator, @query.options)
|
195
195
|
@base = reloaded.base if reloaded
|
196
196
|
end
|
197
197
|
self
|
@@ -24,7 +24,7 @@ module Capybara
|
|
24
24
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
25
25
|
#
|
26
26
|
def find(*args)
|
27
|
-
|
27
|
+
synchronize { all(*args).find! }.tap(&:allow_reload!)
|
28
28
|
end
|
29
29
|
|
30
30
|
##
|
@@ -35,7 +35,7 @@ module Capybara
|
|
35
35
|
# @return [Capybara::Element] The found element
|
36
36
|
#
|
37
37
|
def find_field(locator)
|
38
|
-
find(:
|
38
|
+
find(:field, locator)
|
39
39
|
end
|
40
40
|
alias_method :field_labeled, :find_field
|
41
41
|
|
@@ -47,7 +47,7 @@ module Capybara
|
|
47
47
|
# @return [Capybara::Element] The found element
|
48
48
|
#
|
49
49
|
def find_link(locator)
|
50
|
-
find(:
|
50
|
+
find(:link, locator)
|
51
51
|
end
|
52
52
|
|
53
53
|
##
|
@@ -58,18 +58,18 @@ module Capybara
|
|
58
58
|
# @return [Capybara::Element] The found element
|
59
59
|
#
|
60
60
|
def find_button(locator)
|
61
|
-
find(:
|
61
|
+
find(:button, locator)
|
62
62
|
end
|
63
63
|
|
64
64
|
##
|
65
65
|
#
|
66
66
|
# Find a element on the page, given its id.
|
67
67
|
#
|
68
|
-
# @param [String]
|
68
|
+
# @param [String] id Which element to find
|
69
69
|
# @return [Capybara::Element] The found element
|
70
70
|
#
|
71
71
|
def find_by_id(id)
|
72
|
-
find(:
|
72
|
+
find(:id, id)
|
73
73
|
end
|
74
74
|
|
75
75
|
##
|
@@ -99,20 +99,23 @@ module Capybara
|
|
99
99
|
# page.all('a', :text => 'Home')
|
100
100
|
# page.all('#menu li', :visible => true)
|
101
101
|
#
|
102
|
-
# @
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
102
|
+
# @overload all([kind], locator, options)
|
103
|
+
# @param [:css, :xpath] kind The type of selector
|
104
|
+
# @param [String] locator The selector
|
105
|
+
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
106
|
+
# @option options [Boolean] visible Only find elements that are visible on the page. Setting this to false
|
107
|
+
# (the default, unless Capybara.ignore_hidden_elements = true), finds
|
108
|
+
# invisible _and_ visible elements.
|
109
|
+
# @return [Array[Capybara::Element]] The found elements
|
108
110
|
#
|
109
111
|
def all(*args)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
query = Capybara::Query.new(*args)
|
113
|
+
elements = synchronize do
|
114
|
+
base.find(query.xpath).map do |node|
|
115
|
+
Capybara::Node::Element.new(session, node, self, query)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
Capybara::Result.new(elements, query)
|
116
119
|
end
|
117
120
|
|
118
121
|
##
|
@@ -120,79 +123,14 @@ module Capybara
|
|
120
123
|
# Find the first element on the page matching the given selector
|
121
124
|
# and options, or nil if no element matches.
|
122
125
|
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
# @
|
128
|
-
# @param [Hash{Symbol => Object}] options Additional options; see {all}
|
129
|
-
# @return Capybara::Element The found element
|
126
|
+
# @overload first([kind], locator, options)
|
127
|
+
# @param [:css, :xpath] kind The type of selector
|
128
|
+
# @param [String] locator The selector
|
129
|
+
# @param [Hash] options Additional options; see {all}
|
130
|
+
# @return [Capybara::Element] The found element or nil
|
130
131
|
#
|
131
132
|
def first(*args)
|
132
|
-
|
133
|
-
options = extract_normalized_options(args)
|
134
|
-
found_elements = []
|
135
|
-
|
136
|
-
selector.xpaths.each do |path|
|
137
|
-
find_in_base(selector, path).each do |node|
|
138
|
-
node.without_wait do
|
139
|
-
if matches_options(node, options)
|
140
|
-
found_elements << node
|
141
|
-
return found_elements.last if not Capybara.prefer_visible_elements or node.visible?
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
found_elements.first
|
147
|
-
end
|
148
|
-
|
149
|
-
protected
|
150
|
-
|
151
|
-
def raise_find_error(*args)
|
152
|
-
options = extract_normalized_options(args)
|
153
|
-
normalized = Capybara::Selector.normalize(*args)
|
154
|
-
message = options[:message] || "Unable to find #{normalized.name} #{normalized.locator.inspect}"
|
155
|
-
message = normalized.failure_message.call(self, normalized) if normalized.failure_message
|
156
|
-
raise Capybara::ElementNotFound, message
|
157
|
-
end
|
158
|
-
|
159
|
-
def find_in_base(selector, xpath)
|
160
|
-
base.find(xpath).map do |node|
|
161
|
-
Capybara::Node::Element.new(session, node, self, selector)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def extract_normalized_options(args)
|
166
|
-
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
167
|
-
|
168
|
-
if text = options[:text]
|
169
|
-
options[:text] = Regexp.escape(text) unless text.kind_of?(Regexp)
|
170
|
-
end
|
171
|
-
|
172
|
-
if !options.has_key?(:visible)
|
173
|
-
options[:visible] = Capybara.ignore_hidden_elements
|
174
|
-
end
|
175
|
-
|
176
|
-
if selected = options[:selected]
|
177
|
-
options[:selected] = [selected].flatten
|
178
|
-
end
|
179
|
-
|
180
|
-
options
|
181
|
-
end
|
182
|
-
|
183
|
-
def matches_options(node, options)
|
184
|
-
return false if options[:text] and not node.text.match(options[:text])
|
185
|
-
return false if options[:visible] and not node.visible?
|
186
|
-
return false if options[:with] and not node.value == options[:with]
|
187
|
-
return false if options[:checked] and not node.checked?
|
188
|
-
return false if options[:unchecked] and node.checked?
|
189
|
-
return false if options[:selected] and not has_selected_options?(node, options[:selected])
|
190
|
-
true
|
191
|
-
end
|
192
|
-
|
193
|
-
def has_selected_options?(node, expected)
|
194
|
-
actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text }
|
195
|
-
(expected - actual).empty?
|
133
|
+
all(*args).first
|
196
134
|
end
|
197
135
|
end
|
198
136
|
end
|
@@ -33,29 +33,19 @@ module Capybara
|
|
33
33
|
# @return [Boolean] If the expression exists
|
34
34
|
#
|
35
35
|
def has_selector?(*args)
|
36
|
-
|
37
|
-
wait_until do
|
38
|
-
results = all(*args)
|
39
|
-
|
40
|
-
case
|
41
|
-
when results.empty?
|
42
|
-
false
|
43
|
-
when options[:between]
|
44
|
-
options[:between] === results.size
|
45
|
-
when options[:count]
|
46
|
-
options[:count].to_i == results.size
|
47
|
-
when options[:maximum]
|
48
|
-
options[:maximum].to_i >= results.size
|
49
|
-
when options[:minimum]
|
50
|
-
options[:minimum].to_i <= results.size
|
51
|
-
else
|
52
|
-
results.size > 0
|
53
|
-
end or raise ExpectationNotMet
|
54
|
-
end
|
36
|
+
assert_selector(*args)
|
55
37
|
rescue Capybara::ExpectationNotMet
|
56
38
|
return false
|
57
39
|
end
|
58
40
|
|
41
|
+
def assert_selector(*args)
|
42
|
+
synchronize do
|
43
|
+
result = all(*args)
|
44
|
+
result.matches_count? or raise Capybara::ExpectationNotMet, result.failure_message
|
45
|
+
end
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
59
49
|
##
|
60
50
|
#
|
61
51
|
# Checks if a given selector is not on the page or current node.
|
@@ -65,29 +55,19 @@ module Capybara
|
|
65
55
|
# @return [Boolean]
|
66
56
|
#
|
67
57
|
def has_no_selector?(*args)
|
68
|
-
|
69
|
-
wait_until do
|
70
|
-
results = all(*args)
|
71
|
-
|
72
|
-
case
|
73
|
-
when results.empty?
|
74
|
-
true
|
75
|
-
when options[:between]
|
76
|
-
not(options[:between] === results.size)
|
77
|
-
when options[:count]
|
78
|
-
not(options[:count].to_i == results.size)
|
79
|
-
when options[:maximum]
|
80
|
-
not(options[:maximum].to_i >= results.size)
|
81
|
-
when options[:minimum]
|
82
|
-
not(options[:minimum].to_i <= results.size)
|
83
|
-
else
|
84
|
-
results.empty?
|
85
|
-
end or raise ExpectationNotMet
|
86
|
-
end
|
58
|
+
assert_no_selector(*args)
|
87
59
|
rescue Capybara::ExpectationNotMet
|
88
60
|
return false
|
89
61
|
end
|
90
62
|
|
63
|
+
def assert_no_selector(*args)
|
64
|
+
synchronize do
|
65
|
+
result = all(*args)
|
66
|
+
result.matches_count? and raise Capybara::ExpectationNotMet, result.negative_failure_message
|
67
|
+
end
|
68
|
+
return true
|
69
|
+
end
|
70
|
+
|
91
71
|
##
|
92
72
|
#
|
93
73
|
# Checks if a given XPath expression is on the page or current node.
|
@@ -157,7 +137,7 @@ module Capybara
|
|
157
137
|
# @return [Boolean] If the selector exists
|
158
138
|
#
|
159
139
|
def has_css?(path, options={})
|
160
|
-
|
140
|
+
has_selector?(:css, path, options)
|
161
141
|
end
|
162
142
|
|
163
143
|
##
|
@@ -169,7 +149,7 @@ module Capybara
|
|
169
149
|
# @return [Boolean]
|
170
150
|
#
|
171
151
|
def has_no_css?(path, options={})
|
172
|
-
|
152
|
+
has_no_selector?(:css, path, options)
|
173
153
|
end
|
174
154
|
|
175
155
|
##
|
@@ -177,24 +157,48 @@ module Capybara
|
|
177
157
|
# Checks if the page or current node has the given text content,
|
178
158
|
# ignoring any HTML tags and normalizing whitespace.
|
179
159
|
#
|
160
|
+
# Unlike has_content this only matches displayable text and specifically
|
161
|
+
# excludes text contained within non-display nodes such as script or head tags.
|
162
|
+
#
|
180
163
|
# @param [String] content The text to check for
|
181
164
|
# @return [Boolean] Whether it exists
|
182
165
|
#
|
183
|
-
def
|
184
|
-
|
166
|
+
def has_text?(content)
|
167
|
+
normalized_content = normalize_whitespace(content)
|
168
|
+
|
169
|
+
synchronize do
|
170
|
+
normalize_whitespace(text).match(escape_regexp(normalized_content)) or
|
171
|
+
raise ExpectationNotMet
|
172
|
+
end
|
173
|
+
return true
|
174
|
+
rescue Capybara::ExpectationNotMet
|
175
|
+
return false
|
185
176
|
end
|
177
|
+
alias_method :has_content?, :has_text?
|
186
178
|
|
187
179
|
##
|
188
180
|
#
|
189
181
|
# Checks if the page or current node does not have the given text
|
190
182
|
# content, ignoring any HTML tags and normalizing whitespace.
|
191
183
|
#
|
184
|
+
# Unlike has_content this only matches displayable text and specifically
|
185
|
+
# excludes text contained within non-display nodes such as script or head tags.
|
186
|
+
#
|
192
187
|
# @param [String] content The text to check for
|
193
188
|
# @return [Boolean] Whether it exists
|
194
189
|
#
|
195
|
-
def
|
196
|
-
|
190
|
+
def has_no_text?(content)
|
191
|
+
normalized_content = normalize_whitespace(content)
|
192
|
+
|
193
|
+
synchronize do
|
194
|
+
!normalize_whitespace(text).match(escape_regexp(normalized_content)) or
|
195
|
+
raise ExpectationNotMet
|
196
|
+
end
|
197
|
+
return true
|
198
|
+
rescue Capybara::ExpectationNotMet
|
199
|
+
return false
|
197
200
|
end
|
201
|
+
alias_method :has_no_content?, :has_no_text?
|
198
202
|
|
199
203
|
##
|
200
204
|
#
|
@@ -207,7 +211,7 @@ module Capybara
|
|
207
211
|
# @return [Boolean] Whether it exists
|
208
212
|
#
|
209
213
|
def has_link?(locator, options={})
|
210
|
-
|
214
|
+
has_selector?(:link, locator, options)
|
211
215
|
end
|
212
216
|
|
213
217
|
##
|
@@ -219,7 +223,7 @@ module Capybara
|
|
219
223
|
# @return [Boolean] Whether it doesn't exist
|
220
224
|
#
|
221
225
|
def has_no_link?(locator, options={})
|
222
|
-
|
226
|
+
has_no_selector?(:link, locator, options)
|
223
227
|
end
|
224
228
|
|
225
229
|
##
|
@@ -231,7 +235,7 @@ module Capybara
|
|
231
235
|
# @return [Boolean] Whether it exists
|
232
236
|
#
|
233
237
|
def has_button?(locator)
|
234
|
-
|
238
|
+
has_selector?(:button, locator)
|
235
239
|
end
|
236
240
|
|
237
241
|
##
|
@@ -243,7 +247,7 @@ module Capybara
|
|
243
247
|
# @return [Boolean] Whether it doesn't exist
|
244
248
|
#
|
245
249
|
def has_no_button?(locator)
|
246
|
-
|
250
|
+
has_no_selector?(:button, locator)
|
247
251
|
end
|
248
252
|
|
249
253
|
##
|
@@ -257,13 +261,17 @@ module Capybara
|
|
257
261
|
#
|
258
262
|
# page.has_field?('Name', :with => 'Jonas')
|
259
263
|
#
|
264
|
+
# It is also possible to filter by the field type attribute:
|
265
|
+
#
|
266
|
+
# page.has_field?('Email', :type => 'email')
|
267
|
+
#
|
260
268
|
# @param [String] locator The label, name or id of a field to check for
|
261
269
|
# @option options [String] :with The text content of the field
|
270
|
+
# @option options [String] :type The type attribute of the field
|
262
271
|
# @return [Boolean] Whether it exists
|
263
272
|
#
|
264
273
|
def has_field?(locator, options={})
|
265
|
-
|
266
|
-
has_xpath?(XPath::HTML.field(locator, options), with)
|
274
|
+
has_selector?(:field, locator, options)
|
267
275
|
end
|
268
276
|
|
269
277
|
##
|
@@ -273,11 +281,11 @@ module Capybara
|
|
273
281
|
#
|
274
282
|
# @param [String] locator The label, name or id of a field to check for
|
275
283
|
# @option options [String] :with The text content of the field
|
284
|
+
# @option options [String] :type The type attribute of the field
|
276
285
|
# @return [Boolean] Whether it doesn't exist
|
277
286
|
#
|
278
287
|
def has_no_field?(locator, options={})
|
279
|
-
|
280
|
-
has_no_xpath?(XPath::HTML.field(locator, options), with)
|
288
|
+
has_no_selector?(:field, locator, options)
|
281
289
|
end
|
282
290
|
|
283
291
|
##
|
@@ -290,7 +298,7 @@ module Capybara
|
|
290
298
|
# @return [Boolean] Whether it exists
|
291
299
|
#
|
292
300
|
def has_checked_field?(locator)
|
293
|
-
|
301
|
+
has_selector?(:field, locator, :checked => true)
|
294
302
|
end
|
295
303
|
|
296
304
|
##
|
@@ -303,7 +311,7 @@ module Capybara
|
|
303
311
|
# @return [Boolean] Whether it doesn't exists
|
304
312
|
#
|
305
313
|
def has_no_checked_field?(locator)
|
306
|
-
|
314
|
+
has_no_selector?(:field, locator, :checked => true)
|
307
315
|
end
|
308
316
|
|
309
317
|
##
|
@@ -316,7 +324,7 @@ module Capybara
|
|
316
324
|
# @return [Boolean] Whether it exists
|
317
325
|
#
|
318
326
|
def has_unchecked_field?(locator)
|
319
|
-
|
327
|
+
has_selector?(:field, locator, :unchecked => true)
|
320
328
|
end
|
321
329
|
|
322
330
|
##
|
@@ -329,7 +337,7 @@ module Capybara
|
|
329
337
|
# @return [Boolean] Whether it doesn't exists
|
330
338
|
#
|
331
339
|
def has_no_unchecked_field?(locator)
|
332
|
-
|
340
|
+
has_no_selector?(:field, locator, :unchecked => true)
|
333
341
|
end
|
334
342
|
|
335
343
|
##
|
@@ -345,19 +353,23 @@ module Capybara
|
|
345
353
|
#
|
346
354
|
# page.has_select?('Language', :selected => ['English', 'German'])
|
347
355
|
#
|
348
|
-
# It's also possible to check if
|
356
|
+
# It's also possible to check if the exact set of options exists for
|
349
357
|
# this select box:
|
350
358
|
#
|
351
|
-
# page.has_select?('Language', :options => ['English', 'German'])
|
359
|
+
# page.has_select?('Language', :options => ['English', 'German', 'Spanish'])
|
360
|
+
#
|
361
|
+
# You can also check for a partial set of options:
|
362
|
+
#
|
363
|
+
# page.has_select?('Language', :with_options => ['English', 'German'])
|
352
364
|
#
|
353
365
|
# @param [String] locator The label, name or id of a select box
|
354
366
|
# @option options [Array] :options Options which should be contained in this select box
|
367
|
+
# @option options [Array] :with_options Partial set of options which should be contained in this select box
|
355
368
|
# @option options [String, Array] :selected Options which should be selected
|
356
369
|
# @return [Boolean] Whether it exists
|
357
370
|
#
|
358
371
|
def has_select?(locator, options={})
|
359
|
-
|
360
|
-
has_xpath?(XPath::HTML.select(locator, options), selected)
|
372
|
+
has_selector?(:select, locator, options)
|
361
373
|
end
|
362
374
|
|
363
375
|
##
|
@@ -369,8 +381,7 @@ module Capybara
|
|
369
381
|
# @return [Boolean] Whether it doesn't exist
|
370
382
|
#
|
371
383
|
def has_no_select?(locator, options={})
|
372
|
-
|
373
|
-
has_no_xpath?(XPath::HTML.select(locator, options), selected)
|
384
|
+
has_no_selector?(:select, locator, options)
|
374
385
|
end
|
375
386
|
|
376
387
|
##
|
@@ -387,11 +398,10 @@ module Capybara
|
|
387
398
|
# and the text needs to match exactly.
|
388
399
|
#
|
389
400
|
# @param [String] locator The id or caption of a table
|
390
|
-
# @option options [Array[Array[String]]] :rows A set of rows the table should contain
|
391
401
|
# @return [Boolean] Whether it exist
|
392
402
|
#
|
393
403
|
def has_table?(locator, options={})
|
394
|
-
|
404
|
+
has_selector?(:table, locator, options)
|
395
405
|
end
|
396
406
|
|
397
407
|
##
|
@@ -403,14 +413,42 @@ module Capybara
|
|
403
413
|
# @return [Boolean] Whether it doesn't exist
|
404
414
|
#
|
405
415
|
def has_no_table?(locator, options={})
|
406
|
-
|
416
|
+
has_no_selector?(:table, locator, options)
|
407
417
|
end
|
408
418
|
|
409
|
-
|
419
|
+
def ==(other)
|
420
|
+
if other.respond_to?(:native)
|
421
|
+
self.eql?(other) or native == other.native
|
422
|
+
else
|
423
|
+
self.eql?(other)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
private
|
428
|
+
|
429
|
+
##
|
430
|
+
#
|
431
|
+
# Normalizes whitespace space by stripping leading and trailing
|
432
|
+
# whitespace and replacing sequences of whitespace characters
|
433
|
+
# with a single space.
|
434
|
+
#
|
435
|
+
# @param [String] text Text to normalize
|
436
|
+
# @return [String] Normalized text
|
437
|
+
#
|
438
|
+
def normalize_whitespace(text)
|
439
|
+
text.is_a?(Regexp) ? text : text.gsub(/\s+/, ' ').strip
|
440
|
+
end
|
410
441
|
|
411
|
-
|
412
|
-
|
413
|
-
|
442
|
+
##
|
443
|
+
#
|
444
|
+
# Escapes any characters that would have special meaning in a regexp
|
445
|
+
# if text is not a regexp
|
446
|
+
#
|
447
|
+
# @param [String] text Text to escape
|
448
|
+
# @return [String] Escaped text
|
449
|
+
#
|
450
|
+
def escape_regexp(text)
|
451
|
+
text.is_a?(Regexp) ? text : Regexp.escape(text)
|
414
452
|
end
|
415
453
|
end
|
416
454
|
end
|