capybara 2.0.3 → 2.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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 options a customizable set of options
|
32
|
+
# @option options [Integer] :count (nil) Number of times the text should occur
|
33
|
+
# @option options [Integer] :minimum (nil) Minimum number of times the text should occur
|
34
|
+
# @option options [Integer] :maximum (nil) Maximum number of times the text should occur
|
35
|
+
# @option options [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
|
|
@@ -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)
|
data/lib/capybara/query.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
module Capybara
|
2
2
|
class Query
|
3
|
-
attr_accessor :selector, :locator, :options, :
|
3
|
+
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
4
4
|
|
5
|
-
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum]
|
5
|
+
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait]
|
6
|
+
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
6
7
|
|
7
8
|
def initialize(*args)
|
8
9
|
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
9
10
|
|
10
|
-
unless options.has_key?(:visible)
|
11
|
-
@options[:visible] = Capybara.ignore_hidden_elements
|
12
|
-
end
|
13
|
-
|
14
11
|
if args[0].is_a?(Symbol)
|
15
12
|
@selector = Selector.all[args[0]]
|
16
13
|
@locator = args[1]
|
@@ -20,8 +17,12 @@ module Capybara
|
|
20
17
|
end
|
21
18
|
@selector ||= Selector.all[Capybara.default_selector]
|
22
19
|
|
23
|
-
|
20
|
+
# for compatibility with Capybara 2.0
|
21
|
+
if Capybara.exact_options and @selector == Selector.all[:option]
|
22
|
+
@options[:exact] = true
|
23
|
+
end
|
24
24
|
|
25
|
+
@expression = @selector.call(@locator)
|
25
26
|
assert_valid_keys!
|
26
27
|
end
|
27
28
|
|
@@ -35,34 +36,76 @@ module Capybara
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def matches_filters?(node)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
if options[:text]
|
40
|
+
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text])
|
41
|
+
return false if not node.text(visible).match(regexp)
|
42
|
+
end
|
43
|
+
case visible
|
44
|
+
when :visible then return false unless node.visible?
|
45
|
+
when :hidden then return false if node.visible?
|
46
|
+
end
|
47
|
+
selector.custom_filters.each do |name, filter|
|
48
|
+
if options.has_key?(name)
|
49
|
+
return false unless filter.matches?(node, options[name])
|
50
|
+
elsif filter.default?
|
51
|
+
return false unless filter.matches?(node, filter.default)
|
42
52
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def visible
|
57
|
+
if options.has_key?(:visible)
|
58
|
+
case @options[:visible]
|
59
|
+
when true then :visible
|
60
|
+
when false then :all
|
61
|
+
else @options[:visible]
|
62
|
+
end
|
63
|
+
else
|
64
|
+
if Capybara.ignore_hidden_elements
|
65
|
+
:visible
|
66
|
+
else
|
67
|
+
:all
|
46
68
|
end
|
47
|
-
true
|
48
69
|
end
|
49
70
|
end
|
50
71
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
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
|
72
|
+
def wait
|
73
|
+
if options.has_key?(:wait)
|
74
|
+
@options[:wait] or 0
|
61
75
|
else
|
62
|
-
|
76
|
+
Capybara.default_wait_time
|
63
77
|
end
|
64
78
|
end
|
65
79
|
|
80
|
+
def exact?
|
81
|
+
if options.has_key?(:exact)
|
82
|
+
@options[:exact]
|
83
|
+
else
|
84
|
+
Capybara.exact
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def match
|
89
|
+
if options.has_key?(:match)
|
90
|
+
@options[:match]
|
91
|
+
else
|
92
|
+
Capybara.match
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def xpath(exact=nil)
|
97
|
+
exact = self.exact? if exact == nil
|
98
|
+
if @expression.respond_to?(:to_xpath) and exact
|
99
|
+
@expression.to_xpath(:exact)
|
100
|
+
else
|
101
|
+
@expression.to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def css
|
106
|
+
@expression
|
107
|
+
end
|
108
|
+
|
66
109
|
private
|
67
110
|
|
68
111
|
def assert_valid_keys!
|
@@ -73,6 +116,9 @@ module Capybara
|
|
73
116
|
valid_names = valid_keys.map(&:inspect).join(", ")
|
74
117
|
raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
|
75
118
|
end
|
119
|
+
unless VALID_MATCH.include?(match)
|
120
|
+
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}"
|
121
|
+
end
|
76
122
|
end
|
77
123
|
end
|
78
124
|
end
|
@@ -80,8 +80,12 @@ class Capybara::RackTest::Browser
|
|
80
80
|
@dom ||= Nokogiri::HTML(html)
|
81
81
|
end
|
82
82
|
|
83
|
-
def find(selector)
|
84
|
-
|
83
|
+
def find(format, selector)
|
84
|
+
if format==:css
|
85
|
+
dom.css(selector, Capybara::RackTest::CSSHandlers.new)
|
86
|
+
else
|
87
|
+
dom.xpath(selector)
|
88
|
+
end.map { |node| Capybara::RackTest::Node.new(self, node) }
|
85
89
|
end
|
86
90
|
|
87
91
|
def html
|
@@ -89,7 +93,11 @@ class Capybara::RackTest::Browser
|
|
89
93
|
rescue Rack::Test::Error
|
90
94
|
""
|
91
95
|
end
|
92
|
-
|
96
|
+
|
97
|
+
def title
|
98
|
+
dom.xpath("//title").text
|
99
|
+
end
|
100
|
+
|
93
101
|
protected
|
94
102
|
|
95
103
|
def build_rack_mock_session
|
@@ -62,10 +62,14 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
|
|
62
62
|
response.status
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
66
|
-
browser.find(selector)
|
65
|
+
def find_xpath(selector)
|
66
|
+
browser.find(:xpath, selector)
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
|
+
def find_css(selector)
|
70
|
+
browser.find(:css,selector)
|
71
|
+
end
|
72
|
+
|
69
73
|
def html
|
70
74
|
browser.html
|
71
75
|
end
|
@@ -73,6 +77,10 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
|
|
73
77
|
def dom
|
74
78
|
browser.dom
|
75
79
|
end
|
80
|
+
|
81
|
+
def title
|
82
|
+
browser.title
|
83
|
+
end
|
76
84
|
|
77
85
|
def reset!
|
78
86
|
@browser = nil
|
@@ -17,7 +17,14 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
17
17
|
def params(button)
|
18
18
|
params = {}
|
19
19
|
|
20
|
-
|
20
|
+
form_element_types=[:input, :select, :textarea]
|
21
|
+
form_elements_xpath=XPath.generate do |x|
|
22
|
+
xpath=x.descendant(*form_element_types).where(~x.attr(:form))
|
23
|
+
xpath=xpath.union(x.anywhere(*form_element_types).where(x.attr(:form) == native[:id])) if native[:id]
|
24
|
+
xpath.where(~x.attr(:disabled))
|
25
|
+
end.to_s
|
26
|
+
|
27
|
+
native.xpath(form_elements_xpath).map do |field|
|
21
28
|
case field.name
|
22
29
|
when 'input'
|
23
30
|
if %w(radio checkbox).include? field['type']
|
@@ -1,5 +1,9 @@
|
|
1
1
|
class Capybara::RackTest::Node < Capybara::Driver::Node
|
2
|
-
def
|
2
|
+
def all_text
|
3
|
+
Capybara::Helpers.normalize_whitespace(native.text)
|
4
|
+
end
|
5
|
+
|
6
|
+
def visible_text
|
3
7
|
Capybara::Helpers.normalize_whitespace(unnormalized_text)
|
4
8
|
end
|
5
9
|
|
@@ -15,42 +19,21 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
15
19
|
if (Array === value) && !self[:multiple]
|
16
20
|
raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
|
17
21
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
elsif tag_name == 'input'
|
29
|
-
if (type == 'text' || type == 'password') && self[:maxlength] &&
|
30
|
-
!self[:maxlength].empty?
|
31
|
-
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
32
|
-
# Firefox, allowing no input
|
33
|
-
value = value[0...self[:maxlength].to_i]
|
34
|
-
end
|
35
|
-
if Array === value #Assert multiple attribute is present
|
36
|
-
value.each do |v|
|
37
|
-
new_native = native.clone
|
38
|
-
new_native.remove_attribute('value')
|
39
|
-
native.add_next_sibling(new_native)
|
40
|
-
new_native['value'] = v.to_s
|
41
|
-
end
|
42
|
-
native.remove
|
43
|
-
else
|
44
|
-
native['value'] = value.to_s
|
45
|
-
end
|
46
|
-
elsif tag_name == "textarea"
|
47
|
-
native.content = value.to_s
|
22
|
+
|
23
|
+
if radio?
|
24
|
+
set_radio(value)
|
25
|
+
elsif checkbox?
|
26
|
+
set_checkbox(value)
|
27
|
+
elsif input_field?
|
28
|
+
set_input(value)
|
29
|
+
elsif textarea?
|
30
|
+
native.content = value.to_s unless self[:readonly]
|
48
31
|
end
|
49
32
|
end
|
50
33
|
|
51
34
|
def select_option
|
52
35
|
if select_node['multiple'] != 'multiple'
|
53
|
-
select_node.
|
36
|
+
select_node.find_xpath(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
|
54
37
|
end
|
55
38
|
native["selected"] = 'selected'
|
56
39
|
end
|
@@ -89,14 +72,26 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
89
72
|
string_node.selected?
|
90
73
|
end
|
91
74
|
|
75
|
+
def disabled?
|
76
|
+
if %w(option optgroup).include? tag_name
|
77
|
+
string_node.disabled? || find_xpath("parent::*")[0].disabled?
|
78
|
+
else
|
79
|
+
string_node.disabled?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
92
83
|
def path
|
93
84
|
native.path
|
94
85
|
end
|
95
86
|
|
96
|
-
def
|
87
|
+
def find_xpath(locator)
|
97
88
|
native.xpath(locator).map { |n| self.class.new(driver, n) }
|
98
89
|
end
|
99
|
-
|
90
|
+
|
91
|
+
def find_css(locator)
|
92
|
+
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |n| self.class.new(driver, n) }
|
93
|
+
end
|
94
|
+
|
100
95
|
def ==(other)
|
101
96
|
native == other.native
|
102
97
|
end
|
@@ -125,7 +120,7 @@ private
|
|
125
120
|
|
126
121
|
# a reference to the select node if this is an option node
|
127
122
|
def select_node
|
128
|
-
|
123
|
+
find_xpath('./ancestor::select').first
|
129
124
|
end
|
130
125
|
|
131
126
|
def type
|
@@ -133,6 +128,67 @@ private
|
|
133
128
|
end
|
134
129
|
|
135
130
|
def form
|
136
|
-
native
|
131
|
+
if native[:form]
|
132
|
+
native.xpath("//form[@id='#{native[:form]}']").first
|
133
|
+
else
|
134
|
+
native.ancestors('form').first
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_radio(value)
|
139
|
+
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
|
140
|
+
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
|
141
|
+
native['checked'] = 'checked'
|
142
|
+
end
|
143
|
+
|
144
|
+
def set_checkbox(value)
|
145
|
+
if value && !native['checked']
|
146
|
+
native['checked'] = 'checked'
|
147
|
+
elsif !value && native['checked']
|
148
|
+
native.remove_attribute('checked')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def set_input(value)
|
153
|
+
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
154
|
+
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
155
|
+
# Firefox, allowing no input
|
156
|
+
value = value[0...self[:maxlength].to_i]
|
157
|
+
end
|
158
|
+
if Array === value #Assert multiple attribute is present
|
159
|
+
value.each do |v|
|
160
|
+
new_native = native.clone
|
161
|
+
new_native.remove_attribute('value')
|
162
|
+
native.add_next_sibling(new_native)
|
163
|
+
new_native['value'] = v.to_s
|
164
|
+
end
|
165
|
+
native.remove
|
166
|
+
else
|
167
|
+
native['value'] = value.to_s unless self[:readonly]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def attribute_is_not_blank?(attribute)
|
172
|
+
self[attribute] && !self[attribute].empty?
|
173
|
+
end
|
174
|
+
|
175
|
+
def checkbox?
|
176
|
+
input_field? && type == 'checkbox'
|
177
|
+
end
|
178
|
+
|
179
|
+
def input_field?
|
180
|
+
tag_name == 'input'
|
181
|
+
end
|
182
|
+
|
183
|
+
def radio?
|
184
|
+
input_field? && type == 'radio'
|
185
|
+
end
|
186
|
+
|
187
|
+
def textarea?
|
188
|
+
tag_name == "textarea"
|
189
|
+
end
|
190
|
+
|
191
|
+
def text_or_password?
|
192
|
+
input_field? && (type == 'text' || type == 'password')
|
137
193
|
end
|
138
194
|
end
|