capybara 2.0.3 → 2.1.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.md +82 -0
- data/README.md +57 -52
- data/lib/capybara/cucumber.rb +4 -1
- data/lib/capybara/driver/base.rb +13 -9
- data/lib/capybara/driver/node.rb +18 -6
- data/lib/capybara/helpers.rb +111 -22
- data/lib/capybara/node/actions.rb +30 -25
- data/lib/capybara/node/base.rb +25 -32
- data/lib/capybara/node/document.rb +6 -2
- data/lib/capybara/node/element.rb +44 -7
- data/lib/capybara/node/finders.rb +49 -22
- data/lib/capybara/node/matchers.rb +38 -21
- data/lib/capybara/node/simple.rb +31 -9
- data/lib/capybara/query.rb +72 -26
- data/lib/capybara/rack_test/browser.rb +11 -3
- data/lib/capybara/rack_test/css_handlers.rb +8 -0
- data/lib/capybara/rack_test/driver.rb +11 -3
- data/lib/capybara/rack_test/form.rb +8 -1
- data/lib/capybara/rack_test/node.rb +91 -35
- data/lib/capybara/rails.rb +0 -1
- data/lib/capybara/result.rb +21 -37
- data/lib/capybara/rspec/matchers.rb +60 -31
- data/lib/capybara/selector.rb +46 -13
- data/lib/capybara/selenium/driver.rb +42 -7
- data/lib/capybara/selenium/node.rb +23 -5
- data/lib/capybara/server.rb +1 -1
- data/lib/capybara/session.rb +47 -12
- data/lib/capybara/spec/public/test.js +12 -0
- data/lib/capybara/spec/session/all_spec.rb +9 -8
- data/lib/capybara/spec/session/attach_file_spec.rb +14 -0
- data/lib/capybara/spec/session/check_spec.rb +14 -0
- data/lib/capybara/spec/session/choose_spec.rb +14 -0
- data/lib/capybara/spec/session/click_button_spec.rb +77 -1
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +65 -0
- data/lib/capybara/spec/session/click_link_spec.rb +24 -0
- data/lib/capybara/spec/session/current_scope_spec.rb +29 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +26 -0
- data/lib/capybara/spec/session/find_button_spec.rb +12 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +12 -1
- data/lib/capybara/spec/session/find_field_spec.rb +30 -0
- data/lib/capybara/spec/session/find_link_spec.rb +12 -0
- data/lib/capybara/spec/session/find_spec.rb +264 -16
- data/lib/capybara/spec/session/first_spec.rb +25 -8
- data/lib/capybara/spec/session/has_css_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +10 -2
- data/lib/capybara/spec/session/has_selector_spec.rb +9 -0
- data/lib/capybara/spec/session/has_text_spec.rb +96 -0
- data/lib/capybara/spec/session/has_title_spec.rb +47 -0
- data/lib/capybara/spec/session/node_spec.rb +48 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +10 -2
- data/lib/capybara/spec/session/save_page_spec.rb +30 -0
- data/lib/capybara/spec/session/select_spec.rb +65 -0
- data/lib/capybara/spec/session/text_spec.rb +31 -0
- data/lib/capybara/spec/session/title_spec.rb +16 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +14 -0
- data/lib/capybara/spec/session/unselect_spec.rb +42 -0
- data/lib/capybara/spec/session/visit_spec.rb +3 -3
- data/lib/capybara/spec/session/within_frame_spec.rb +14 -0
- data/lib/capybara/spec/session/within_spec.rb +3 -3
- data/lib/capybara/spec/spec_helper.rb +7 -2
- data/lib/capybara/spec/views/form.erb +39 -2
- data/lib/capybara/spec/views/frame_child.erb +9 -0
- data/lib/capybara/spec/views/frame_parent.erb +8 -0
- data/lib/capybara/spec/views/with_base_tag.erb +10 -0
- data/lib/capybara/spec/views/with_count.erb +7 -0
- data/lib/capybara/spec/views/with_hover.erb +17 -0
- data/lib/capybara/spec/views/with_html.erb +23 -2
- data/lib/capybara/spec/views/with_js.erb +5 -0
- data/lib/capybara/spec/views/with_scope.erb +6 -1
- data/lib/capybara/spec/views/with_title.erb +1 -0
- data/lib/capybara/spec/views/within_frames.erb +1 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara.rb +43 -62
- data/spec/basic_node_spec.rb +75 -24
- data/spec/dsl_spec.rb +2 -1
- data/spec/rack_test_spec.rb +4 -3
- data/spec/rspec/matchers_spec.rb +105 -17
- data/spec/server_spec.rb +15 -8
- data/spec/spec_helper.rb +2 -1
- data.tar.gz.sig +0 -0
- metadata +82 -22
- metadata.gz.sig +0 -0
|
@@ -9,8 +9,8 @@ module Capybara
|
|
|
9
9
|
#
|
|
10
10
|
# @param [String] locator Text, id or value of link or button
|
|
11
11
|
#
|
|
12
|
-
def click_link_or_button(locator)
|
|
13
|
-
find(:link_or_button, locator).click
|
|
12
|
+
def click_link_or_button(locator, options={})
|
|
13
|
+
find(:link_or_button, locator, options).click
|
|
14
14
|
end
|
|
15
15
|
alias_method :click_on, :click_link_or_button
|
|
16
16
|
|
|
@@ -20,9 +20,11 @@ module Capybara
|
|
|
20
20
|
# alt text inside the link.
|
|
21
21
|
#
|
|
22
22
|
# @param [String] locator Text, id or text of link
|
|
23
|
+
# @param options
|
|
24
|
+
# @option options [String] :href The value the href attribute must be
|
|
23
25
|
#
|
|
24
|
-
def click_link(locator)
|
|
25
|
-
find(:link, locator).click
|
|
26
|
+
def click_link(locator, options={})
|
|
27
|
+
find(:link, locator, options).click
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
##
|
|
@@ -31,8 +33,8 @@ module Capybara
|
|
|
31
33
|
#
|
|
32
34
|
# @param [String] locator Text, id or value of button
|
|
33
35
|
#
|
|
34
|
-
def click_button(locator)
|
|
35
|
-
find(:button, locator).click
|
|
36
|
+
def click_button(locator, options={})
|
|
37
|
+
find(:button, locator, options).click
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
##
|
|
@@ -42,12 +44,13 @@ module Capybara
|
|
|
42
44
|
#
|
|
43
45
|
# page.fill_in 'Name', :with => 'Bob'
|
|
44
46
|
#
|
|
45
|
-
# @param [String] locator
|
|
46
|
-
# @param [Hash{:with => String}]
|
|
47
|
+
# @param [String] locator Which field to fill in
|
|
48
|
+
# @param [Hash{:with => String}] options The value to fill in
|
|
47
49
|
#
|
|
48
50
|
def fill_in(locator, options={})
|
|
49
51
|
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
|
50
|
-
|
|
52
|
+
with = options.delete(:with)
|
|
53
|
+
find(:fillable_field, locator, options).set(with)
|
|
51
54
|
end
|
|
52
55
|
|
|
53
56
|
##
|
|
@@ -59,8 +62,8 @@ module Capybara
|
|
|
59
62
|
#
|
|
60
63
|
# @param [String] locator Which radio button to choose
|
|
61
64
|
#
|
|
62
|
-
def choose(locator)
|
|
63
|
-
find(:radio_button, locator).set(true)
|
|
65
|
+
def choose(locator, options={})
|
|
66
|
+
find(:radio_button, locator, options).set(true)
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
##
|
|
@@ -72,8 +75,8 @@ module Capybara
|
|
|
72
75
|
#
|
|
73
76
|
# @param [String] locator Which check box to check
|
|
74
77
|
#
|
|
75
|
-
def check(locator)
|
|
76
|
-
find(:checkbox, locator).set(true)
|
|
78
|
+
def check(locator, options={})
|
|
79
|
+
find(:checkbox, locator, options).set(true)
|
|
77
80
|
end
|
|
78
81
|
|
|
79
82
|
##
|
|
@@ -85,8 +88,8 @@ module Capybara
|
|
|
85
88
|
#
|
|
86
89
|
# @param [String] locator Which check box to uncheck
|
|
87
90
|
#
|
|
88
|
-
def uncheck(locator)
|
|
89
|
-
find(:checkbox, locator).set(false)
|
|
91
|
+
def uncheck(locator, options={})
|
|
92
|
+
find(:checkbox, locator, options).set(false)
|
|
90
93
|
end
|
|
91
94
|
|
|
92
95
|
##
|
|
@@ -97,14 +100,15 @@ module Capybara
|
|
|
97
100
|
#
|
|
98
101
|
# page.select 'March', :from => 'Month'
|
|
99
102
|
#
|
|
100
|
-
# @param [String] value
|
|
101
|
-
# @param [Hash{:from => String}]
|
|
103
|
+
# @param [String] value Which option to select
|
|
104
|
+
# @param [Hash{:from => String}] options The id, name or label of the select box
|
|
102
105
|
#
|
|
103
106
|
def select(value, options={})
|
|
104
107
|
if options.has_key?(:from)
|
|
105
|
-
|
|
108
|
+
from = options.delete(:from)
|
|
109
|
+
find(:select, from, options).find(:option, value, options).select_option
|
|
106
110
|
else
|
|
107
|
-
find(:option, value).select_option
|
|
111
|
+
find(:option, value, options).select_option
|
|
108
112
|
end
|
|
109
113
|
end
|
|
110
114
|
|
|
@@ -116,14 +120,15 @@ module Capybara
|
|
|
116
120
|
#
|
|
117
121
|
# page.unselect 'March', :from => 'Month'
|
|
118
122
|
#
|
|
119
|
-
# @param [String] value
|
|
120
|
-
# @param [Hash{:from => String}]
|
|
123
|
+
# @param [String] value Which option to unselect
|
|
124
|
+
# @param [Hash{:from => String}] options The id, name or label of the select box
|
|
121
125
|
#
|
|
122
126
|
def unselect(value, options={})
|
|
123
127
|
if options.has_key?(:from)
|
|
124
|
-
|
|
128
|
+
from = options.delete(:from)
|
|
129
|
+
find(:select, from, options).find(:option, value, options).unselect_option
|
|
125
130
|
else
|
|
126
|
-
find(:option, value).unselect_option
|
|
131
|
+
find(:option, value, options).unselect_option
|
|
127
132
|
end
|
|
128
133
|
end
|
|
129
134
|
|
|
@@ -137,11 +142,11 @@ module Capybara
|
|
|
137
142
|
# @param [String] locator Which field to attach the file to
|
|
138
143
|
# @param [String] path The path of the file that will be attached, or an array of paths
|
|
139
144
|
#
|
|
140
|
-
def attach_file(locator, path)
|
|
145
|
+
def attach_file(locator, path, options={})
|
|
141
146
|
Array(path).each do |p|
|
|
142
147
|
raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
|
|
143
148
|
end
|
|
144
|
-
find(:file_field, locator).set(path)
|
|
149
|
+
find(:file_field, locator, options).set(path)
|
|
145
150
|
end
|
|
146
151
|
end
|
|
147
152
|
end
|
data/lib/capybara/node/base.rb
CHANGED
|
@@ -31,7 +31,6 @@ module Capybara
|
|
|
31
31
|
def initialize(session, base)
|
|
32
32
|
@session = session
|
|
33
33
|
@base = base
|
|
34
|
-
@unsynchronized = false
|
|
35
34
|
end
|
|
36
35
|
|
|
37
36
|
# overridden in subclasses, e.g. Capybara::Node::Element
|
|
@@ -64,50 +63,44 @@ module Capybara
|
|
|
64
63
|
# until a certain amount of time passes. The amount of time defaults to
|
|
65
64
|
# {Capybara.default_wait_time} and can be overriden through the `seconds`
|
|
66
65
|
# argument. This time is compared with the system time to see how much
|
|
67
|
-
# time has passed. If the return value of
|
|
66
|
+
# time has passed. If the return value of `Time.now` is stubbed out,
|
|
68
67
|
# Capybara will raise `Capybara::FrozenInTime`.
|
|
69
68
|
#
|
|
70
|
-
# @param
|
|
69
|
+
# @param [Integer] seconds Number of seconds to retry this block
|
|
71
70
|
# @return [Object] The result of the given block
|
|
72
|
-
# @raise
|
|
71
|
+
# @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
|
|
73
72
|
#
|
|
74
73
|
def synchronize(seconds=Capybara.default_wait_time)
|
|
75
74
|
start_time = Time.now
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
if session.synchronized
|
|
78
77
|
yield
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
else
|
|
79
|
+
session.synchronized = true
|
|
80
|
+
begin
|
|
81
|
+
yield
|
|
82
|
+
rescue => e
|
|
83
|
+
raise e unless driver.wait?
|
|
84
|
+
raise e unless catch_error?(e)
|
|
85
|
+
raise e if (Time.now - start_time) >= seconds
|
|
86
|
+
sleep(0.05)
|
|
87
|
+
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
|
|
88
|
+
reload if Capybara.automatic_reload
|
|
89
|
+
retry
|
|
90
|
+
ensure
|
|
91
|
+
session.synchronized = false
|
|
92
|
+
end
|
|
88
93
|
end
|
|
89
94
|
end
|
|
90
95
|
|
|
91
|
-
##
|
|
92
|
-
#
|
|
93
|
-
# Within the given block, prevent synchronize from having any effect.
|
|
94
|
-
#
|
|
95
|
-
# This is an internal method which should not be called unless you are
|
|
96
|
-
# absolutely sure of what you're doing.
|
|
97
|
-
#
|
|
98
|
-
# @api private
|
|
99
|
-
# @return [Object] The result of the given block
|
|
100
|
-
#
|
|
101
|
-
def unsynchronized
|
|
102
|
-
orig = @unsynchronized
|
|
103
|
-
@unsynchronized = true
|
|
104
|
-
yield
|
|
105
|
-
ensure
|
|
106
|
-
@unsynchronized = orig
|
|
107
|
-
end
|
|
108
|
-
|
|
109
96
|
protected
|
|
110
97
|
|
|
98
|
+
def catch_error?(error)
|
|
99
|
+
(driver.invalid_element_errors + [Capybara::ElementNotFound]).any? do |type|
|
|
100
|
+
error.is_a?(type)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
111
104
|
def driver
|
|
112
105
|
session.driver
|
|
113
106
|
end
|
|
@@ -42,10 +42,25 @@ module Capybara
|
|
|
42
42
|
|
|
43
43
|
##
|
|
44
44
|
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
# Retrieve the text of the element. If `Capybara.ignore_hidden_elements`
|
|
46
|
+
# is `true`, which it is by default, then this will return only text
|
|
47
|
+
# which is visible. The exact semantics of this may differ between
|
|
48
|
+
# drivers, but generally any text within elements with `display:none` is
|
|
49
|
+
# ignored. This behaviour can be overridden by passing `:all` to this
|
|
50
|
+
# method.
|
|
51
|
+
#
|
|
52
|
+
# @param [:all, :visible] type Whether to return only visible or all text
|
|
53
|
+
# @return [String] The text of the element
|
|
54
|
+
#
|
|
55
|
+
def text(type=nil)
|
|
56
|
+
type ||= :all unless Capybara.ignore_hidden_elements or Capybara.visible_text_only
|
|
57
|
+
synchronize do
|
|
58
|
+
if type == :all
|
|
59
|
+
base.all_text
|
|
60
|
+
else
|
|
61
|
+
base.visible_text
|
|
62
|
+
end
|
|
63
|
+
end
|
|
49
64
|
end
|
|
50
65
|
|
|
51
66
|
##
|
|
@@ -103,6 +118,14 @@ module Capybara
|
|
|
103
118
|
synchronize { base.click }
|
|
104
119
|
end
|
|
105
120
|
|
|
121
|
+
##
|
|
122
|
+
#
|
|
123
|
+
# Hover on the Element
|
|
124
|
+
#
|
|
125
|
+
def hover
|
|
126
|
+
synchronize { base.hover }
|
|
127
|
+
end
|
|
128
|
+
|
|
106
129
|
##
|
|
107
130
|
#
|
|
108
131
|
# @return [String] The tag name of the element
|
|
@@ -142,6 +165,16 @@ module Capybara
|
|
|
142
165
|
synchronize { base.selected? }
|
|
143
166
|
end
|
|
144
167
|
|
|
168
|
+
##
|
|
169
|
+
#
|
|
170
|
+
# Whether or not the element is disabled.
|
|
171
|
+
#
|
|
172
|
+
# @return [Boolean] Whether the element is disabled
|
|
173
|
+
#
|
|
174
|
+
def disabled?
|
|
175
|
+
synchronize { base.disabled? }
|
|
176
|
+
end
|
|
177
|
+
|
|
145
178
|
##
|
|
146
179
|
#
|
|
147
180
|
# An XPath expression describing where on the page the element can be found
|
|
@@ -179,15 +212,19 @@ module Capybara
|
|
|
179
212
|
|
|
180
213
|
def reload
|
|
181
214
|
if @allow_reload
|
|
182
|
-
|
|
183
|
-
|
|
215
|
+
begin
|
|
216
|
+
reloaded = parent.reload.first(@query.name, @query.locator, @query.options)
|
|
217
|
+
@base = reloaded.base if reloaded
|
|
218
|
+
rescue => e
|
|
219
|
+
raise e unless catch_error?(e)
|
|
220
|
+
end
|
|
184
221
|
end
|
|
185
222
|
self
|
|
186
223
|
end
|
|
187
224
|
|
|
188
225
|
def inspect
|
|
189
226
|
%(#<Capybara::Element tag="#{tag_name}" path="#{path}">)
|
|
190
|
-
rescue NotSupportedByDriverError
|
|
227
|
+
rescue NotSupportedByDriverError, 'Capybara::Node::Element#inspect'
|
|
191
228
|
%(#<Capybara::Element tag="#{tag_name}">)
|
|
192
229
|
end
|
|
193
230
|
end
|
|
@@ -19,11 +19,29 @@ module Capybara
|
|
|
19
19
|
# page.find('li', :text => 'Quox').click_link('Delete')
|
|
20
20
|
#
|
|
21
21
|
# @param (see Capybara::Node::Finders#all)
|
|
22
|
-
# @
|
|
23
|
-
# @
|
|
22
|
+
# @option options [Boolean] match The matching strategy to use.
|
|
23
|
+
# @option options [false, Numeric] wait How long to wait for the element to appear.
|
|
24
|
+
#
|
|
25
|
+
# @return [Capybara::Element] The found element
|
|
26
|
+
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
|
24
27
|
#
|
|
25
28
|
def find(*args)
|
|
26
|
-
|
|
29
|
+
query = Capybara::Query.new(*args)
|
|
30
|
+
synchronize(query.wait) do
|
|
31
|
+
if query.match == :smart or query.match == :prefer_exact
|
|
32
|
+
result = resolve_query(query, true)
|
|
33
|
+
result = resolve_query(query, false) if result.size == 0 and not query.exact?
|
|
34
|
+
else
|
|
35
|
+
result = resolve_query(query)
|
|
36
|
+
end
|
|
37
|
+
if query.match == :one or query.match == :smart and result.size > 1
|
|
38
|
+
raise Capybara::Ambiguous.new("Ambiguous match, found #{result.size} elements matching #{query.description}")
|
|
39
|
+
end
|
|
40
|
+
if result.size == 0
|
|
41
|
+
raise Capybara::ElementNotFound.new("Unable to find #{query.description}")
|
|
42
|
+
end
|
|
43
|
+
result.first
|
|
44
|
+
end.tap(&:allow_reload!)
|
|
27
45
|
end
|
|
28
46
|
|
|
29
47
|
##
|
|
@@ -33,8 +51,8 @@ module Capybara
|
|
|
33
51
|
# @param [String] locator Which field to find
|
|
34
52
|
# @return [Capybara::Element] The found element
|
|
35
53
|
#
|
|
36
|
-
def find_field(locator)
|
|
37
|
-
find(:field, locator)
|
|
54
|
+
def find_field(locator, options={})
|
|
55
|
+
find(:field, locator, options)
|
|
38
56
|
end
|
|
39
57
|
alias_method :field_labeled, :find_field
|
|
40
58
|
|
|
@@ -45,8 +63,8 @@ module Capybara
|
|
|
45
63
|
# @param [String] locator Which link to find
|
|
46
64
|
# @return [Capybara::Element] The found element
|
|
47
65
|
#
|
|
48
|
-
def find_link(locator)
|
|
49
|
-
find(:link, locator)
|
|
66
|
+
def find_link(locator, options={})
|
|
67
|
+
find(:link, locator, options)
|
|
50
68
|
end
|
|
51
69
|
|
|
52
70
|
##
|
|
@@ -56,8 +74,8 @@ module Capybara
|
|
|
56
74
|
# @param [String] locator Which button to find
|
|
57
75
|
# @return [Capybara::Element] The found element
|
|
58
76
|
#
|
|
59
|
-
def find_button(locator)
|
|
60
|
-
find(:button, locator)
|
|
77
|
+
def find_button(locator, options={})
|
|
78
|
+
find(:button, locator, options)
|
|
61
79
|
end
|
|
62
80
|
|
|
63
81
|
##
|
|
@@ -67,8 +85,8 @@ module Capybara
|
|
|
67
85
|
# @param [String] id Which element to find
|
|
68
86
|
# @return [Capybara::Element] The found element
|
|
69
87
|
#
|
|
70
|
-
def find_by_id(id)
|
|
71
|
-
find(:id, id)
|
|
88
|
+
def find_by_id(id, options={})
|
|
89
|
+
find(:id, id, options)
|
|
72
90
|
end
|
|
73
91
|
|
|
74
92
|
##
|
|
@@ -103,18 +121,12 @@ module Capybara
|
|
|
103
121
|
# @param [String] locator The selector
|
|
104
122
|
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
|
105
123
|
# @option options [Boolean] visible Only find elements that are visible on the page. Setting this to false
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
# @return [
|
|
124
|
+
# finds invisible _and_ visible elements.
|
|
125
|
+
# @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially
|
|
126
|
+
# @return [Capybara::Result] A collection of found elements
|
|
109
127
|
#
|
|
110
128
|
def all(*args)
|
|
111
|
-
|
|
112
|
-
elements = synchronize do
|
|
113
|
-
base.find(query.xpath).map do |node|
|
|
114
|
-
Capybara::Node::Element.new(session, node, self, query)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
Capybara::Result.new(elements, query)
|
|
129
|
+
resolve_query(Capybara::Query.new(*args))
|
|
118
130
|
end
|
|
119
131
|
|
|
120
132
|
##
|
|
@@ -125,12 +137,27 @@ module Capybara
|
|
|
125
137
|
# @overload first([kind], locator, options)
|
|
126
138
|
# @param [:css, :xpath] kind The type of selector
|
|
127
139
|
# @param [String] locator The selector
|
|
128
|
-
# @param [Hash] options Additional options; see {all}
|
|
140
|
+
# @param [Hash] options Additional options; see {#all}
|
|
129
141
|
# @return [Capybara::Element] The found element or nil
|
|
130
142
|
#
|
|
131
143
|
def first(*args)
|
|
132
144
|
all(*args).first
|
|
133
145
|
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def resolve_query(query, exact=nil)
|
|
150
|
+
elements = synchronize do
|
|
151
|
+
if query.selector.format==:css
|
|
152
|
+
base.find_css(query.css)
|
|
153
|
+
else
|
|
154
|
+
base.find_xpath(query.xpath(exact))
|
|
155
|
+
end.map do |node|
|
|
156
|
+
Capybara::Node::Element.new(session, node, self, query)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
Capybara::Result.new(elements, query)
|
|
160
|
+
end
|
|
134
161
|
end
|
|
135
162
|
end
|
|
136
163
|
end
|
|
@@ -13,7 +13,7 @@ module Capybara
|
|
|
13
13
|
# By default it will check if the expression occurs at least once,
|
|
14
14
|
# but a different number can be specified.
|
|
15
15
|
#
|
|
16
|
-
# page.has_selector?('p
|
|
16
|
+
# page.has_selector?('p.foo', :count => 4)
|
|
17
17
|
#
|
|
18
18
|
# This will check if the expression occurs exactly 4 times.
|
|
19
19
|
#
|
|
@@ -28,8 +28,12 @@ module Capybara
|
|
|
28
28
|
# page.has_selector?(:xpath, XPath.descendant(:p))
|
|
29
29
|
#
|
|
30
30
|
# @param (see Capybara::Node::Finders#all)
|
|
31
|
-
# @
|
|
32
|
-
# @
|
|
31
|
+
# @param args
|
|
32
|
+
# @option args [Integer] :count (nil) Number of times the text should occur
|
|
33
|
+
# @option args [Integer] :minimum (nil) Minimum number of times the text should occur
|
|
34
|
+
# @option args [Integer] :maximum (nil) Maximum number of times the text should occur
|
|
35
|
+
# @option args [Range] :between (nil) Range of times that should contain number of times text occurs
|
|
36
|
+
# @return [Boolean] If the expression exists
|
|
33
37
|
#
|
|
34
38
|
def has_selector?(*args)
|
|
35
39
|
assert_selector(*args)
|
|
@@ -71,7 +75,7 @@ module Capybara
|
|
|
71
75
|
#
|
|
72
76
|
# page.assert_selector('li', :text => 'Horse', :visible => true)
|
|
73
77
|
#
|
|
74
|
-
#
|
|
78
|
+
# `assert_selector` can also accept XPath expressions generated by the
|
|
75
79
|
# XPath gem:
|
|
76
80
|
#
|
|
77
81
|
# page.assert_selector(:xpath, XPath.descendant(:p))
|
|
@@ -193,17 +197,26 @@ module Capybara
|
|
|
193
197
|
# Checks if the page or current node has the given text content,
|
|
194
198
|
# ignoring any HTML tags and normalizing whitespace.
|
|
195
199
|
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
200
|
+
# By default it will check if the text occurs at least once,
|
|
201
|
+
# but a different number can be specified.
|
|
202
|
+
#
|
|
203
|
+
# page.has_text?('lorem ipsum', between: 2..4)
|
|
204
|
+
#
|
|
205
|
+
# This will check if the text occurs from 2 to 4 times.
|
|
198
206
|
#
|
|
199
|
-
# @
|
|
200
|
-
#
|
|
207
|
+
# @overload has_text?([type], text, [options])
|
|
208
|
+
# @param [:all, :visible] type Whether to check for only visible or all text
|
|
209
|
+
# @param [String, Regexp] text The text/regexp to check for
|
|
210
|
+
# @param [Hash] options additional options
|
|
211
|
+
# @option options [Integer] :count (nil) Number of times the text should occur
|
|
212
|
+
# @option options [Integer] :minimum (nil) Minimum number of times the text should occur
|
|
213
|
+
# @option options [Integer] :maximum (nil) Maximum number of times the text should occur
|
|
214
|
+
# @option options [Range] :between (nil) Range of times that should contain number of times text occurs
|
|
215
|
+
# @return [Boolean] Whether it exists
|
|
201
216
|
#
|
|
202
|
-
def has_text?(
|
|
217
|
+
def has_text?(*args)
|
|
203
218
|
synchronize do
|
|
204
|
-
unless
|
|
205
|
-
raise ExpectationNotMet
|
|
206
|
-
end
|
|
219
|
+
raise ExpectationNotMet unless text_found?(*args)
|
|
207
220
|
end
|
|
208
221
|
return true
|
|
209
222
|
rescue Capybara::ExpectationNotMet
|
|
@@ -216,17 +229,12 @@ module Capybara
|
|
|
216
229
|
# Checks if the page or current node does not have the given text
|
|
217
230
|
# content, ignoring any HTML tags and normalizing whitespace.
|
|
218
231
|
#
|
|
219
|
-
#
|
|
220
|
-
#
|
|
232
|
+
# @param (see #has_text?)
|
|
233
|
+
# @return [Boolean] Whether it doesn't exist
|
|
221
234
|
#
|
|
222
|
-
|
|
223
|
-
# @return [Boolean] Whether it doesn't exist
|
|
224
|
-
#
|
|
225
|
-
def has_no_text?(content)
|
|
235
|
+
def has_no_text?(*args)
|
|
226
236
|
synchronize do
|
|
227
|
-
if
|
|
228
|
-
raise ExpectationNotMet
|
|
229
|
-
end
|
|
237
|
+
raise ExpectationNotMet if text_found?(*args)
|
|
230
238
|
end
|
|
231
239
|
return true
|
|
232
240
|
rescue Capybara::ExpectationNotMet
|
|
@@ -299,6 +307,8 @@ module Capybara
|
|
|
299
307
|
#
|
|
300
308
|
# page.has_field?('Email', :type => 'email')
|
|
301
309
|
#
|
|
310
|
+
# Note: 'textarea' and 'select' are valid type values, matching the associated tag names.
|
|
311
|
+
#
|
|
302
312
|
# @param [String] locator The label, name or id of a field to check for
|
|
303
313
|
# @option options [String] :with The text content of the field
|
|
304
314
|
# @option options [String] :type The type attribute of the field
|
|
@@ -450,6 +460,13 @@ module Capybara
|
|
|
450
460
|
|
|
451
461
|
private
|
|
452
462
|
|
|
463
|
+
def text_found?(*args)
|
|
464
|
+
type = args.shift if args.first.is_a?(Symbol) or args.first.nil?
|
|
465
|
+
content, options = args
|
|
466
|
+
count = Capybara::Helpers.normalize_whitespace(text(type)).scan(Capybara::Helpers.to_regexp(content)).count
|
|
467
|
+
|
|
468
|
+
Capybara::Helpers.matches_count?(count, options || {})
|
|
469
|
+
end
|
|
453
470
|
end
|
|
454
471
|
end
|
|
455
472
|
end
|
data/lib/capybara/node/simple.rb
CHANGED
|
@@ -26,7 +26,7 @@ module Capybara
|
|
|
26
26
|
#
|
|
27
27
|
# @return [String] The text of the element
|
|
28
28
|
#
|
|
29
|
-
def text
|
|
29
|
+
def text(type=nil)
|
|
30
30
|
native.text
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -36,8 +36,8 @@ module Capybara
|
|
|
36
36
|
#
|
|
37
37
|
# element[:title] # => HTML title attribute
|
|
38
38
|
#
|
|
39
|
-
# @param [Symbol]
|
|
40
|
-
# @return [String]
|
|
39
|
+
# @param [Symbol] name The attribute name to retrieve
|
|
40
|
+
# @return [String] The value of the attribute
|
|
41
41
|
#
|
|
42
42
|
def [](name)
|
|
43
43
|
attr_name = name.to_s
|
|
@@ -108,6 +108,15 @@ module Capybara
|
|
|
108
108
|
native[:checked]
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
+
##
|
|
112
|
+
#
|
|
113
|
+
# Whether or not the element is disabled.
|
|
114
|
+
#
|
|
115
|
+
# @return [Boolean] Whether the element is disabled
|
|
116
|
+
def disabled?
|
|
117
|
+
native[:disabled]
|
|
118
|
+
end
|
|
119
|
+
|
|
111
120
|
##
|
|
112
121
|
#
|
|
113
122
|
# Whether or not the element is selected.
|
|
@@ -118,7 +127,7 @@ module Capybara
|
|
|
118
127
|
native[:selected]
|
|
119
128
|
end
|
|
120
129
|
|
|
121
|
-
def synchronize
|
|
130
|
+
def synchronize(seconds=nil)
|
|
122
131
|
yield # simple nodes don't need to wait
|
|
123
132
|
end
|
|
124
133
|
|
|
@@ -126,13 +135,26 @@ module Capybara
|
|
|
126
135
|
# no op
|
|
127
136
|
end
|
|
128
137
|
|
|
129
|
-
def
|
|
130
|
-
|
|
138
|
+
def title
|
|
139
|
+
native.xpath("//title").first.text
|
|
131
140
|
end
|
|
132
141
|
|
|
133
|
-
def
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
def has_title?(content)
|
|
143
|
+
title.match(Capybara::Helpers.to_regexp(content))
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def has_no_title?(content)
|
|
147
|
+
not has_title?(content)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def resolve_query(query, exact=nil)
|
|
153
|
+
elements = if query.selector.format == :css
|
|
154
|
+
native.css(query.css)
|
|
155
|
+
else
|
|
156
|
+
native.xpath(query.xpath(exact))
|
|
157
|
+
end.map do |node|
|
|
136
158
|
self.class.new(node)
|
|
137
159
|
end
|
|
138
160
|
Capybara::Result.new(elements, query)
|