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
@@ -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
|