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