capybara 1.1.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{History.txt → History.md} +138 -0
- data/License.txt +22 -0
- data/README.md +850 -0
- data/lib/capybara/cucumber.rb +2 -5
- data/lib/capybara/driver/base.rb +6 -6
- data/lib/capybara/driver/node.rb +3 -2
- data/lib/capybara/dsl.rb +13 -124
- data/lib/capybara/helpers.rb +33 -0
- data/lib/capybara/node/actions.rb +16 -30
- data/lib/capybara/node/base.rb +56 -13
- data/lib/capybara/node/element.rb +18 -30
- data/lib/capybara/node/finders.rb +28 -90
- data/lib/capybara/node/matchers.rb +121 -73
- data/lib/capybara/node/simple.rb +13 -11
- data/lib/capybara/query.rb +78 -0
- data/lib/capybara/rack_test/browser.rb +27 -39
- data/lib/capybara/rack_test/driver.rb +13 -3
- data/lib/capybara/rack_test/node.rb +31 -2
- data/lib/capybara/result.rb +72 -0
- data/lib/capybara/rspec/features.rb +4 -1
- data/lib/capybara/rspec/matchers.rb +33 -63
- data/lib/capybara/rspec.rb +7 -4
- data/lib/capybara/selector.rb +97 -34
- data/lib/capybara/selenium/driver.rb +15 -62
- data/lib/capybara/selenium/node.rb +14 -21
- data/lib/capybara/server.rb +32 -27
- data/lib/capybara/session.rb +90 -50
- data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
- 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 +3 -0
- data/lib/capybara/spec/session/all_spec.rb +61 -59
- data/lib/capybara/spec/session/assert_selector.rb +123 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +72 -55
- data/lib/capybara/spec/session/body_spec.rb +21 -0
- data/lib/capybara/spec/session/check_spec.rb +68 -48
- data/lib/capybara/spec/session/choose_spec.rb +32 -18
- data/lib/capybara/spec/session/click_button_spec.rb +263 -232
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +40 -29
- data/lib/capybara/spec/session/click_link_spec.rb +96 -96
- data/lib/capybara/spec/session/current_url_spec.rb +88 -10
- data/lib/capybara/spec/session/evaluate_script_spec.rb +6 -0
- data/lib/capybara/spec/session/execute_script_spec.rb +7 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +119 -103
- data/lib/capybara/spec/session/find_button_spec.rb +16 -14
- data/lib/capybara/spec/session/find_by_id_spec.rb +16 -14
- data/lib/capybara/spec/session/find_field_spec.rb +23 -21
- data/lib/capybara/spec/session/find_link_spec.rb +15 -14
- data/lib/capybara/spec/session/find_spec.rb +93 -115
- data/lib/capybara/spec/session/first_spec.rb +51 -85
- data/lib/capybara/spec/session/has_button_spec.rb +22 -24
- data/lib/capybara/spec/session/has_css_spec.rb +190 -205
- data/lib/capybara/spec/session/has_field_spec.rb +170 -144
- data/lib/capybara/spec/session/has_link_spec.rb +26 -29
- data/lib/capybara/spec/session/has_select_spec.rb +161 -109
- data/lib/capybara/spec/session/has_selector_spec.rb +94 -100
- data/lib/capybara/spec/session/has_table_spec.rb +22 -88
- data/lib/capybara/spec/session/has_text_spec.rb +195 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +100 -96
- data/lib/capybara/spec/session/headers.rb +4 -17
- data/lib/capybara/spec/session/html_spec.rb +15 -0
- data/lib/capybara/spec/session/node_spec.rb +205 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +42 -0
- data/lib/capybara/spec/session/response_code.rb +4 -17
- data/lib/capybara/spec/session/save_page_spec.rb +46 -0
- data/lib/capybara/spec/session/screenshot.rb +13 -0
- data/lib/capybara/spec/session/select_spec.rb +99 -88
- data/lib/capybara/spec/session/source_spec.rb +12 -0
- data/lib/capybara/spec/session/text_spec.rb +15 -12
- data/lib/capybara/spec/session/uncheck_spec.rb +22 -17
- data/lib/capybara/spec/session/unselect_spec.rb +69 -58
- data/lib/capybara/spec/session/visit_spec.rb +74 -0
- data/lib/capybara/spec/session/within_frame_spec.rb +31 -0
- data/lib/capybara/spec/session/within_spec.rb +118 -131
- data/lib/capybara/spec/session/within_window_spec.rb +38 -0
- data/lib/capybara/spec/spec_helper.rb +84 -0
- data/lib/capybara/spec/test_app.rb +32 -6
- data/lib/capybara/spec/views/form.erb +12 -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 +9 -4
- data/lib/capybara/spec/views/with_js.erb +11 -7
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara.rb +125 -6
- data/spec/basic_node_spec.rb +17 -5
- data/spec/capybara_spec.rb +9 -0
- data/spec/dsl_spec.rb +31 -17
- data/spec/rack_test_spec.rb +157 -0
- data/spec/result_spec.rb +51 -0
- data/spec/rspec/features_spec.rb +19 -2
- data/spec/rspec/matchers_spec.rb +170 -89
- data/spec/rspec_spec.rb +1 -3
- data/spec/selenium_spec.rb +53 -0
- data/spec/server_spec.rb +37 -25
- data/spec/spec_helper.rb +1 -30
- metadata +39 -31
- 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/spec/session/javascript.rb +0 -306
- data/lib/capybara/spec/session.rb +0 -154
- data/lib/capybara/util/save_and_open_page.rb +0 -44
- 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/save_and_open_page_spec.rb +0 -155
- 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
|
@@ -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,29 +47,29 @@ 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
|
##
|
|
54
54
|
#
|
|
55
|
-
# Find a button on the page. The
|
|
55
|
+
# Find a button on the page. The button can be found by its id, name or value.
|
|
56
56
|
#
|
|
57
57
|
# @param [String] locator Which button to find
|
|
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
|
|
@@ -25,33 +25,14 @@ module Capybara
|
|
|
25
25
|
# has_selector? can also accept XPath expressions generated by the
|
|
26
26
|
# XPath gem:
|
|
27
27
|
#
|
|
28
|
-
# xpath
|
|
29
|
-
# page.has_selector?(:xpath, xpath)
|
|
28
|
+
# page.has_selector?(:xpath, XPath.descendant(:p))
|
|
30
29
|
#
|
|
31
30
|
# @param (see Capybara::Node::Finders#all)
|
|
32
31
|
# @option options [Integer] :count (nil) Number of times the expression should occur
|
|
33
32
|
# @return [Boolean] If the expression exists
|
|
34
33
|
#
|
|
35
34
|
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
|
|
35
|
+
assert_selector(*args)
|
|
55
36
|
rescue Capybara::ExpectationNotMet
|
|
56
37
|
return false
|
|
57
38
|
end
|
|
@@ -65,29 +46,64 @@ module Capybara
|
|
|
65
46
|
# @return [Boolean]
|
|
66
47
|
#
|
|
67
48
|
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
|
|
49
|
+
assert_no_selector(*args)
|
|
87
50
|
rescue Capybara::ExpectationNotMet
|
|
88
51
|
return false
|
|
89
52
|
end
|
|
90
53
|
|
|
54
|
+
##
|
|
55
|
+
#
|
|
56
|
+
# Asserts that a given selector is on the page or current node.
|
|
57
|
+
#
|
|
58
|
+
# page.assert_selector('p#foo')
|
|
59
|
+
# page.assert_selector(:xpath, './/p[@id="foo"]')
|
|
60
|
+
# page.assert_selector(:foo)
|
|
61
|
+
#
|
|
62
|
+
# By default it will check if the expression occurs at least once,
|
|
63
|
+
# but a different number can be specified.
|
|
64
|
+
#
|
|
65
|
+
# page.assert_selector('p#foo', :count => 4)
|
|
66
|
+
#
|
|
67
|
+
# This will check if the expression occurs exactly 4 times.
|
|
68
|
+
#
|
|
69
|
+
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
70
|
+
# such as :text and :visible.
|
|
71
|
+
#
|
|
72
|
+
# page.assert_selector('li', :text => 'Horse', :visible => true)
|
|
73
|
+
#
|
|
74
|
+
# {assert_selector} can also accept XPath expressions generated by the
|
|
75
|
+
# XPath gem:
|
|
76
|
+
#
|
|
77
|
+
# page.assert_selector(:xpath, XPath.descendant(:p))
|
|
78
|
+
#
|
|
79
|
+
# @param (see Capybara::Node::Finders#all)
|
|
80
|
+
# @option options [Integer] :count (nil) Number of times the expression should occur
|
|
81
|
+
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
|
82
|
+
#
|
|
83
|
+
def assert_selector(*args)
|
|
84
|
+
synchronize do
|
|
85
|
+
result = all(*args)
|
|
86
|
+
result.matches_count? or raise Capybara::ExpectationNotMet, result.failure_message
|
|
87
|
+
end
|
|
88
|
+
return true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
#
|
|
93
|
+
# Asserts that a given selector is not on the page or current node.
|
|
94
|
+
# Usage is identical to Capybara::Node::Matchers#assert_selector
|
|
95
|
+
#
|
|
96
|
+
# @param (see Capybara::Node::Finders#assert_selector)
|
|
97
|
+
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
|
98
|
+
#
|
|
99
|
+
def assert_no_selector(*args)
|
|
100
|
+
synchronize do
|
|
101
|
+
result = all(*args)
|
|
102
|
+
result.matches_count? and raise Capybara::ExpectationNotMet, result.negative_failure_message
|
|
103
|
+
end
|
|
104
|
+
return true
|
|
105
|
+
end
|
|
106
|
+
|
|
91
107
|
##
|
|
92
108
|
#
|
|
93
109
|
# Checks if a given XPath expression is on the page or current node.
|
|
@@ -157,7 +173,7 @@ module Capybara
|
|
|
157
173
|
# @return [Boolean] If the selector exists
|
|
158
174
|
#
|
|
159
175
|
def has_css?(path, options={})
|
|
160
|
-
|
|
176
|
+
has_selector?(:css, path, options)
|
|
161
177
|
end
|
|
162
178
|
|
|
163
179
|
##
|
|
@@ -169,7 +185,7 @@ module Capybara
|
|
|
169
185
|
# @return [Boolean]
|
|
170
186
|
#
|
|
171
187
|
def has_no_css?(path, options={})
|
|
172
|
-
|
|
188
|
+
has_no_selector?(:css, path, options)
|
|
173
189
|
end
|
|
174
190
|
|
|
175
191
|
##
|
|
@@ -177,24 +193,46 @@ module Capybara
|
|
|
177
193
|
# Checks if the page or current node has the given text content,
|
|
178
194
|
# ignoring any HTML tags and normalizing whitespace.
|
|
179
195
|
#
|
|
196
|
+
# This only matches displayable text and specifically excludes text
|
|
197
|
+
# contained within non-display nodes such as script or head tags.
|
|
198
|
+
#
|
|
180
199
|
# @param [String] content The text to check for
|
|
181
200
|
# @return [Boolean] Whether it exists
|
|
182
201
|
#
|
|
183
|
-
def
|
|
184
|
-
|
|
202
|
+
def has_text?(content)
|
|
203
|
+
synchronize do
|
|
204
|
+
unless Capybara::Helpers.normalize_whitespace(text).match(Capybara::Helpers.to_regexp(content))
|
|
205
|
+
raise ExpectationNotMet
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
return true
|
|
209
|
+
rescue Capybara::ExpectationNotMet
|
|
210
|
+
return false
|
|
185
211
|
end
|
|
212
|
+
alias_method :has_content?, :has_text?
|
|
186
213
|
|
|
187
214
|
##
|
|
188
215
|
#
|
|
189
216
|
# Checks if the page or current node does not have the given text
|
|
190
217
|
# content, ignoring any HTML tags and normalizing whitespace.
|
|
191
218
|
#
|
|
219
|
+
# This only matches displayable text and specifically excludes text
|
|
220
|
+
# contained within non-display nodes such as script or head tags.
|
|
221
|
+
#
|
|
192
222
|
# @param [String] content The text to check for
|
|
193
|
-
# @return [Boolean] Whether it
|
|
223
|
+
# @return [Boolean] Whether it doesn't exist
|
|
194
224
|
#
|
|
195
|
-
def
|
|
196
|
-
|
|
225
|
+
def has_no_text?(content)
|
|
226
|
+
synchronize do
|
|
227
|
+
if Capybara::Helpers.normalize_whitespace(text).match(Capybara::Helpers.to_regexp(content))
|
|
228
|
+
raise ExpectationNotMet
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
return true
|
|
232
|
+
rescue Capybara::ExpectationNotMet
|
|
233
|
+
return false
|
|
197
234
|
end
|
|
235
|
+
alias_method :has_no_content?, :has_no_text?
|
|
198
236
|
|
|
199
237
|
##
|
|
200
238
|
#
|
|
@@ -207,7 +245,7 @@ module Capybara
|
|
|
207
245
|
# @return [Boolean] Whether it exists
|
|
208
246
|
#
|
|
209
247
|
def has_link?(locator, options={})
|
|
210
|
-
|
|
248
|
+
has_selector?(:link, locator, options)
|
|
211
249
|
end
|
|
212
250
|
|
|
213
251
|
##
|
|
@@ -219,7 +257,7 @@ module Capybara
|
|
|
219
257
|
# @return [Boolean] Whether it doesn't exist
|
|
220
258
|
#
|
|
221
259
|
def has_no_link?(locator, options={})
|
|
222
|
-
|
|
260
|
+
has_no_selector?(:link, locator, options)
|
|
223
261
|
end
|
|
224
262
|
|
|
225
263
|
##
|
|
@@ -231,7 +269,7 @@ module Capybara
|
|
|
231
269
|
# @return [Boolean] Whether it exists
|
|
232
270
|
#
|
|
233
271
|
def has_button?(locator)
|
|
234
|
-
|
|
272
|
+
has_selector?(:button, locator)
|
|
235
273
|
end
|
|
236
274
|
|
|
237
275
|
##
|
|
@@ -243,7 +281,7 @@ module Capybara
|
|
|
243
281
|
# @return [Boolean] Whether it doesn't exist
|
|
244
282
|
#
|
|
245
283
|
def has_no_button?(locator)
|
|
246
|
-
|
|
284
|
+
has_no_selector?(:button, locator)
|
|
247
285
|
end
|
|
248
286
|
|
|
249
287
|
##
|
|
@@ -257,13 +295,17 @@ module Capybara
|
|
|
257
295
|
#
|
|
258
296
|
# page.has_field?('Name', :with => 'Jonas')
|
|
259
297
|
#
|
|
298
|
+
# It is also possible to filter by the field type attribute:
|
|
299
|
+
#
|
|
300
|
+
# page.has_field?('Email', :type => 'email')
|
|
301
|
+
#
|
|
260
302
|
# @param [String] locator The label, name or id of a field to check for
|
|
261
303
|
# @option options [String] :with The text content of the field
|
|
304
|
+
# @option options [String] :type The type attribute of the field
|
|
262
305
|
# @return [Boolean] Whether it exists
|
|
263
306
|
#
|
|
264
307
|
def has_field?(locator, options={})
|
|
265
|
-
|
|
266
|
-
has_xpath?(XPath::HTML.field(locator, options), with)
|
|
308
|
+
has_selector?(:field, locator, options)
|
|
267
309
|
end
|
|
268
310
|
|
|
269
311
|
##
|
|
@@ -273,11 +315,11 @@ module Capybara
|
|
|
273
315
|
#
|
|
274
316
|
# @param [String] locator The label, name or id of a field to check for
|
|
275
317
|
# @option options [String] :with The text content of the field
|
|
318
|
+
# @option options [String] :type The type attribute of the field
|
|
276
319
|
# @return [Boolean] Whether it doesn't exist
|
|
277
320
|
#
|
|
278
321
|
def has_no_field?(locator, options={})
|
|
279
|
-
|
|
280
|
-
has_no_xpath?(XPath::HTML.field(locator, options), with)
|
|
322
|
+
has_no_selector?(:field, locator, options)
|
|
281
323
|
end
|
|
282
324
|
|
|
283
325
|
##
|
|
@@ -290,7 +332,7 @@ module Capybara
|
|
|
290
332
|
# @return [Boolean] Whether it exists
|
|
291
333
|
#
|
|
292
334
|
def has_checked_field?(locator)
|
|
293
|
-
|
|
335
|
+
has_selector?(:field, locator, :checked => true)
|
|
294
336
|
end
|
|
295
337
|
|
|
296
338
|
##
|
|
@@ -303,7 +345,7 @@ module Capybara
|
|
|
303
345
|
# @return [Boolean] Whether it doesn't exists
|
|
304
346
|
#
|
|
305
347
|
def has_no_checked_field?(locator)
|
|
306
|
-
|
|
348
|
+
has_no_selector?(:field, locator, :checked => true)
|
|
307
349
|
end
|
|
308
350
|
|
|
309
351
|
##
|
|
@@ -316,7 +358,7 @@ module Capybara
|
|
|
316
358
|
# @return [Boolean] Whether it exists
|
|
317
359
|
#
|
|
318
360
|
def has_unchecked_field?(locator)
|
|
319
|
-
|
|
361
|
+
has_selector?(:field, locator, :unchecked => true)
|
|
320
362
|
end
|
|
321
363
|
|
|
322
364
|
##
|
|
@@ -329,7 +371,7 @@ module Capybara
|
|
|
329
371
|
# @return [Boolean] Whether it doesn't exists
|
|
330
372
|
#
|
|
331
373
|
def has_no_unchecked_field?(locator)
|
|
332
|
-
|
|
374
|
+
has_no_selector?(:field, locator, :unchecked => true)
|
|
333
375
|
end
|
|
334
376
|
|
|
335
377
|
##
|
|
@@ -345,19 +387,23 @@ module Capybara
|
|
|
345
387
|
#
|
|
346
388
|
# page.has_select?('Language', :selected => ['English', 'German'])
|
|
347
389
|
#
|
|
348
|
-
# It's also possible to check if
|
|
390
|
+
# It's also possible to check if the exact set of options exists for
|
|
349
391
|
# this select box:
|
|
350
392
|
#
|
|
351
|
-
# page.has_select?('Language', :options => ['English', 'German'])
|
|
393
|
+
# page.has_select?('Language', :options => ['English', 'German', 'Spanish'])
|
|
394
|
+
#
|
|
395
|
+
# You can also check for a partial set of options:
|
|
396
|
+
#
|
|
397
|
+
# page.has_select?('Language', :with_options => ['English', 'German'])
|
|
352
398
|
#
|
|
353
399
|
# @param [String] locator The label, name or id of a select box
|
|
354
400
|
# @option options [Array] :options Options which should be contained in this select box
|
|
401
|
+
# @option options [Array] :with_options Partial set of options which should be contained in this select box
|
|
355
402
|
# @option options [String, Array] :selected Options which should be selected
|
|
356
403
|
# @return [Boolean] Whether it exists
|
|
357
404
|
#
|
|
358
405
|
def has_select?(locator, options={})
|
|
359
|
-
|
|
360
|
-
has_xpath?(XPath::HTML.select(locator, options), selected)
|
|
406
|
+
has_selector?(:select, locator, options)
|
|
361
407
|
end
|
|
362
408
|
|
|
363
409
|
##
|
|
@@ -369,8 +415,7 @@ module Capybara
|
|
|
369
415
|
# @return [Boolean] Whether it doesn't exist
|
|
370
416
|
#
|
|
371
417
|
def has_no_select?(locator, options={})
|
|
372
|
-
|
|
373
|
-
has_no_xpath?(XPath::HTML.select(locator, options), selected)
|
|
418
|
+
has_no_selector?(:select, locator, options)
|
|
374
419
|
end
|
|
375
420
|
|
|
376
421
|
##
|
|
@@ -387,11 +432,10 @@ module Capybara
|
|
|
387
432
|
# and the text needs to match exactly.
|
|
388
433
|
#
|
|
389
434
|
# @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
435
|
# @return [Boolean] Whether it exist
|
|
392
436
|
#
|
|
393
437
|
def has_table?(locator, options={})
|
|
394
|
-
|
|
438
|
+
has_selector?(:table, locator, options)
|
|
395
439
|
end
|
|
396
440
|
|
|
397
441
|
##
|
|
@@ -403,15 +447,19 @@ module Capybara
|
|
|
403
447
|
# @return [Boolean] Whether it doesn't exist
|
|
404
448
|
#
|
|
405
449
|
def has_no_table?(locator, options={})
|
|
406
|
-
|
|
450
|
+
has_no_selector?(:table, locator, options)
|
|
407
451
|
end
|
|
408
452
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
453
|
+
def ==(other)
|
|
454
|
+
if other.respond_to?(:native)
|
|
455
|
+
self.eql?(other) or native == other.native
|
|
456
|
+
else
|
|
457
|
+
self.eql?(other)
|
|
458
|
+
end
|
|
414
459
|
end
|
|
460
|
+
|
|
461
|
+
private
|
|
462
|
+
|
|
415
463
|
end
|
|
416
464
|
end
|
|
417
465
|
end
|
data/lib/capybara/node/simple.rb
CHANGED
|
@@ -95,7 +95,7 @@ module Capybara
|
|
|
95
95
|
# @return [Boolean] Whether the element is visible
|
|
96
96
|
#
|
|
97
97
|
def visible?
|
|
98
|
-
native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none')]").size == 0
|
|
98
|
+
native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or name()='script' or name()='head']").size == 0
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
##
|
|
@@ -118,22 +118,24 @@ module Capybara
|
|
|
118
118
|
native[:selected]
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
def
|
|
122
|
-
#
|
|
121
|
+
def synchronize
|
|
122
|
+
yield # simple nodes don't need to wait
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
def
|
|
126
|
-
|
|
125
|
+
def allow_reload!
|
|
126
|
+
# no op
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def find_in_base(selector, xpath)
|
|
132
|
-
native.xpath(xpath).map { |node| self.class.new(node) }
|
|
129
|
+
def unsynchronized
|
|
130
|
+
yield # simple nodes don't need to wait
|
|
133
131
|
end
|
|
134
132
|
|
|
135
|
-
def
|
|
136
|
-
|
|
133
|
+
def all(*args)
|
|
134
|
+
query = Capybara::Query.new(*args)
|
|
135
|
+
elements = native.xpath(query.xpath).map do |node|
|
|
136
|
+
self.class.new(node)
|
|
137
|
+
end
|
|
138
|
+
Capybara::Result.new(elements, query)
|
|
137
139
|
end
|
|
138
140
|
end
|
|
139
141
|
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Capybara
|
|
2
|
+
class Query
|
|
3
|
+
attr_accessor :selector, :locator, :options, :xpath, :find, :negative
|
|
4
|
+
|
|
5
|
+
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum]
|
|
6
|
+
|
|
7
|
+
def initialize(*args)
|
|
8
|
+
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
|
9
|
+
|
|
10
|
+
unless options.has_key?(:visible)
|
|
11
|
+
@options[:visible] = Capybara.ignore_hidden_elements
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if args[0].is_a?(Symbol)
|
|
15
|
+
@selector = Selector.all[args[0]]
|
|
16
|
+
@locator = args[1]
|
|
17
|
+
else
|
|
18
|
+
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
|
|
19
|
+
@locator = args[0]
|
|
20
|
+
end
|
|
21
|
+
@selector ||= Selector.all[Capybara.default_selector]
|
|
22
|
+
|
|
23
|
+
@xpath = @selector.call(@locator).to_s
|
|
24
|
+
|
|
25
|
+
assert_valid_keys!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def name; selector.name; end
|
|
29
|
+
def label; selector.label or selector.name; end
|
|
30
|
+
|
|
31
|
+
def description
|
|
32
|
+
@description = "#{label} #{locator.inspect}"
|
|
33
|
+
@description << " with text #{options[:text].inspect}" if options[:text]
|
|
34
|
+
@description
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def matches_filters?(node)
|
|
38
|
+
node.unsynchronized do
|
|
39
|
+
if options[:text]
|
|
40
|
+
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text])
|
|
41
|
+
return false if not node.text.match(regexp)
|
|
42
|
+
end
|
|
43
|
+
return false if options[:visible] and not node.visible?
|
|
44
|
+
selector.custom_filters.each do |name, block|
|
|
45
|
+
return false if options.has_key?(name) and not block.call(node, options[name])
|
|
46
|
+
end
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def matches_count?(count)
|
|
52
|
+
case
|
|
53
|
+
when options[:between]
|
|
54
|
+
options[:between] === count
|
|
55
|
+
when options[:count]
|
|
56
|
+
options[:count].to_i == count
|
|
57
|
+
when options[:maximum]
|
|
58
|
+
options[:maximum].to_i >= count
|
|
59
|
+
when options[:minimum]
|
|
60
|
+
options[:minimum].to_i <= count
|
|
61
|
+
else
|
|
62
|
+
count > 0
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def assert_valid_keys!
|
|
69
|
+
valid_keys = VALID_KEYS + @selector.custom_filters.keys
|
|
70
|
+
invalid_keys = @options.keys - valid_keys
|
|
71
|
+
unless invalid_keys.empty?
|
|
72
|
+
invalid_names = invalid_keys.map(&:inspect).join(", ")
|
|
73
|
+
valid_names = valid_keys.map(&:inspect).join(", ")
|
|
74
|
+
raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|