capybara 2.0.3 → 2.1.0.beta1
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.tar.gz.sig +0 -0
- data/History.md +73 -0
- data/README.md +52 -5
- data/lib/capybara.rb +44 -62
- 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 +24 -19
- data/lib/capybara/node/base.rb +25 -32
- data/lib/capybara/node/document.rb +6 -2
- data/lib/capybara/node/element.rb +45 -7
- data/lib/capybara/node/finders.rb +48 -21
- data/lib/capybara/node/matchers.rb +38 -21
- data/lib/capybara/node/simple.rb +29 -7
- 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 +92 -36
- data/lib/capybara/rails.rb +1 -2
- 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 -6
- data/lib/capybara/selenium/node.rb +23 -5
- data/lib/capybara/session.rb +46 -11
- 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 +14 -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 +258 -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 +43 -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 +6 -1
- 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 +21 -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/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 +8 -8
- data/spec/spec_helper.rb +2 -1
- metadata +83 -23
- metadata.gz.sig +0 -0
data/lib/capybara/helpers.rb
CHANGED
@@ -1,31 +1,120 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
module Capybara
|
4
|
+
|
5
|
+
# @api private
|
4
6
|
module Helpers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
extend self
|
8
|
+
|
9
|
+
##
|
10
|
+
#
|
11
|
+
# Normalizes whitespace space by stripping leading and trailing
|
12
|
+
# whitespace and replacing sequences of whitespace characters
|
13
|
+
# with a single space.
|
14
|
+
#
|
15
|
+
# @param [String] text Text to normalize
|
16
|
+
# @return [String] Normalized text
|
17
|
+
#
|
18
|
+
def normalize_whitespace(text)
|
19
|
+
text.to_s.gsub(/[[:space:]]+/, ' ').strip
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
#
|
24
|
+
# Escapes any characters that would have special meaning in a regexp
|
25
|
+
# if text is not a regexp
|
26
|
+
#
|
27
|
+
# @param [String] text Text to escape
|
28
|
+
# @return [String] Escaped text
|
29
|
+
#
|
30
|
+
def to_regexp(text)
|
31
|
+
text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
#
|
36
|
+
# Injects a `<base>` tag into the given HTML code, pointing to
|
37
|
+
# `Capybara.asset_host`.
|
38
|
+
#
|
39
|
+
# @param [String] html HTML code to inject into
|
40
|
+
# @param [String] The modified HTML code
|
41
|
+
#
|
42
|
+
def inject_asset_host(html)
|
43
|
+
if Capybara.asset_host
|
44
|
+
if Nokogiri::HTML(html).css("base").empty? and match = html.match(/<head[^<]*?>/)
|
45
|
+
html.clone.insert match.end(0), "<base href='#{Capybara.asset_host}' />"
|
46
|
+
end
|
47
|
+
else
|
48
|
+
html
|
17
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
#
|
54
|
+
# Checks if the given count matches the given count options. By default,
|
55
|
+
# when no options are given, count should be larger than zero.
|
56
|
+
#
|
57
|
+
# @param [Integer] count The actual number. Should be coercible via Integer()
|
58
|
+
# @option [Range] between Count must be within the given range
|
59
|
+
# @option [Integer] count Count must be exactly this
|
60
|
+
# @option [Integer] maximum Count must be smaller than or equal to this value
|
61
|
+
# @option [Integer] minimum Count must be larger than or equal to this value
|
62
|
+
#
|
63
|
+
def matches_count?(count, options={})
|
64
|
+
case
|
65
|
+
when options[:between]
|
66
|
+
options[:between] === count
|
67
|
+
when options[:count]
|
68
|
+
Integer(options[:count]) == count
|
69
|
+
when options[:maximum]
|
70
|
+
Integer(options[:maximum]) >= count
|
71
|
+
when options[:minimum]
|
72
|
+
Integer(options[:minimum]) <= count
|
73
|
+
else
|
74
|
+
count > 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
#
|
80
|
+
# Generates a failure message given a description of the query and count
|
81
|
+
# options.
|
82
|
+
#
|
83
|
+
# @param [String] description Description of a query
|
84
|
+
# @option [Range] between Count should have been within the given range
|
85
|
+
# @option [Integer] count Count should have been exactly this
|
86
|
+
# @option [Integer] maximum Count should have been smaller than or equal to this value
|
87
|
+
# @option [Integer] minimum Count should have been larger than or equal to this value
|
88
|
+
#
|
89
|
+
def failure_message(description, options={})
|
90
|
+
message = "expected to find #{description}"
|
91
|
+
if options[:count]
|
92
|
+
message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
|
93
|
+
elsif options[:between]
|
94
|
+
message << " between #{options[:between].first} and #{options[:between].last} times"
|
95
|
+
elsif options[:maximum]
|
96
|
+
message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}"
|
97
|
+
elsif options[:minimum]
|
98
|
+
message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}"
|
99
|
+
end
|
100
|
+
message
|
101
|
+
end
|
18
102
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
103
|
+
##
|
104
|
+
#
|
105
|
+
# A poor man's `pluralize`. Given two declensions, one singular and one
|
106
|
+
# plural, as well as a count, this will pick the correct declension. This
|
107
|
+
# way we can generate gramatically correct error message.
|
108
|
+
#
|
109
|
+
# @param [String] singular The singular form of the word
|
110
|
+
# @param [String] plural The plural form of the word
|
111
|
+
# @param [Integer] count The number of items
|
112
|
+
#
|
113
|
+
def declension(singular, plural, count)
|
114
|
+
if count == 1
|
115
|
+
singular
|
116
|
+
else
|
117
|
+
plural
|
29
118
|
end
|
30
119
|
end
|
31
120
|
end
|
@@ -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
|
##
|
@@ -47,7 +49,8 @@ module Capybara
|
|
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
|
##
|
@@ -102,9 +105,10 @@ module Capybara
|
|
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
|
|
@@ -121,9 +125,10 @@ module Capybara
|
|
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,26 @@ 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] Whether to return only visible or all text
|
53
|
+
#
|
54
|
+
# @return [String] The text of the element
|
55
|
+
#
|
56
|
+
def text(type=nil)
|
57
|
+
type ||= :all unless Capybara.ignore_hidden_elements or Capybara.visible_text_only
|
58
|
+
synchronize do
|
59
|
+
if type == :all
|
60
|
+
base.all_text
|
61
|
+
else
|
62
|
+
base.visible_text
|
63
|
+
end
|
64
|
+
end
|
49
65
|
end
|
50
66
|
|
51
67
|
##
|
@@ -103,6 +119,14 @@ module Capybara
|
|
103
119
|
synchronize { base.click }
|
104
120
|
end
|
105
121
|
|
122
|
+
##
|
123
|
+
#
|
124
|
+
# Hover on the Element
|
125
|
+
#
|
126
|
+
def hover
|
127
|
+
synchronize { base.hover }
|
128
|
+
end
|
129
|
+
|
106
130
|
##
|
107
131
|
#
|
108
132
|
# @return [String] The tag name of the element
|
@@ -142,6 +166,16 @@ module Capybara
|
|
142
166
|
synchronize { base.selected? }
|
143
167
|
end
|
144
168
|
|
169
|
+
##
|
170
|
+
#
|
171
|
+
# Whether or not the element is disabled.
|
172
|
+
#
|
173
|
+
# @return [Boolean] Whether the element is disabled
|
174
|
+
#
|
175
|
+
def disabled?
|
176
|
+
synchronize { base.disabled? }
|
177
|
+
end
|
178
|
+
|
145
179
|
##
|
146
180
|
#
|
147
181
|
# An XPath expression describing where on the page the element can be found
|
@@ -179,15 +213,19 @@ module Capybara
|
|
179
213
|
|
180
214
|
def reload
|
181
215
|
if @allow_reload
|
182
|
-
|
183
|
-
|
216
|
+
begin
|
217
|
+
reloaded = parent.reload.first(@query.name, @query.locator, @query.options)
|
218
|
+
@base = reloaded.base if reloaded
|
219
|
+
rescue => e
|
220
|
+
raise e unless catch_error?(e)
|
221
|
+
end
|
184
222
|
end
|
185
223
|
self
|
186
224
|
end
|
187
225
|
|
188
226
|
def inspect
|
189
227
|
%(#<Capybara::Element tag="#{tag_name}" path="#{path}">)
|
190
|
-
rescue NotSupportedByDriverError
|
228
|
+
rescue NotSupportedByDriverError, 'Capybara::Node::Element#inspect'
|
191
229
|
%(#<Capybara::Element tag="#{tag_name}">)
|
192
230
|
end
|
193
231
|
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
|
##
|
@@ -131,6 +143,21 @@ module Capybara
|
|
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
|