capybara 2.13.0 → 2.18.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.
- checksums.yaml +5 -5
- data/History.md +218 -18
- data/README.md +54 -23
- data/lib/capybara/config.rb +132 -0
- data/lib/capybara/cucumber.rb +1 -0
- data/lib/capybara/driver/base.rb +14 -0
- data/lib/capybara/dsl.rb +1 -3
- data/lib/capybara/helpers.rb +3 -3
- data/lib/capybara/minitest/spec.rb +14 -37
- data/lib/capybara/minitest.rb +95 -114
- data/lib/capybara/node/actions.rb +10 -10
- data/lib/capybara/node/base.rb +7 -2
- data/lib/capybara/node/element.rb +9 -3
- data/lib/capybara/node/finders.rb +92 -18
- data/lib/capybara/node/matchers.rb +21 -9
- data/lib/capybara/node/simple.rb +5 -0
- data/lib/capybara/queries/ancestor_query.rb +25 -0
- data/lib/capybara/queries/base_query.rb +12 -3
- data/lib/capybara/queries/current_path_query.rb +13 -9
- data/lib/capybara/queries/selector_query.rb +62 -23
- data/lib/capybara/queries/sibling_query.rb +25 -0
- data/lib/capybara/queries/text_query.rb +10 -5
- data/lib/capybara/queries/title_query.rb +1 -0
- data/lib/capybara/rack_test/browser.rb +13 -5
- data/lib/capybara/rack_test/driver.rb +6 -1
- data/lib/capybara/rack_test/form.rb +4 -3
- data/lib/capybara/rack_test/node.rb +1 -1
- data/lib/capybara/rspec/compound.rb +95 -0
- data/lib/capybara/rspec/matcher_proxies.rb +45 -0
- data/lib/capybara/rspec/matchers.rb +108 -7
- data/lib/capybara/rspec.rb +3 -1
- data/lib/capybara/selector/filter.rb +13 -41
- data/lib/capybara/selector/filter_set.rb +30 -4
- data/lib/capybara/selector/filters/base.rb +33 -0
- data/lib/capybara/selector/filters/expression_filter.rb +40 -0
- data/lib/capybara/selector/filters/node_filter.rb +27 -0
- data/lib/capybara/selector/selector.rb +36 -15
- data/lib/capybara/selector.rb +63 -42
- data/lib/capybara/selenium/driver.rb +177 -33
- data/lib/capybara/selenium/node.rb +106 -55
- data/lib/capybara/server.rb +6 -5
- data/lib/capybara/session/config.rb +114 -0
- data/lib/capybara/session/matchers.rb +15 -4
- data/lib/capybara/session.rb +178 -65
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/test.js +18 -3
- data/lib/capybara/spec/session/accept_alert_spec.rb +9 -1
- data/lib/capybara/spec/session/accept_prompt_spec.rb +29 -1
- data/lib/capybara/spec/session/all_spec.rb +13 -1
- data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +24 -8
- data/lib/capybara/spec/session/assert_selector.rb +1 -1
- data/lib/capybara/spec/session/assert_text.rb +8 -0
- data/lib/capybara/spec/session/assert_title.rb +22 -9
- data/lib/capybara/spec/session/attach_file_spec.rb +8 -1
- data/lib/capybara/spec/session/check_spec.rb +4 -4
- data/lib/capybara/spec/session/choose_spec.rb +2 -2
- data/lib/capybara/spec/session/click_button_spec.rb +1 -1
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +3 -3
- data/lib/capybara/spec/session/click_link_spec.rb +1 -1
- data/lib/capybara/spec/session/current_url_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -1
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +1 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +8 -2
- data/lib/capybara/spec/session/find_field_spec.rb +1 -0
- data/lib/capybara/spec/session/find_spec.rb +8 -6
- data/lib/capybara/spec/session/first_spec.rb +10 -5
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_css_spec.rb +11 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +52 -7
- data/lib/capybara/spec/session/has_link_spec.rb +4 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +64 -6
- data/lib/capybara/spec/session/has_selector_spec.rb +1 -3
- data/lib/capybara/spec/session/has_text_spec.rb +5 -3
- data/lib/capybara/spec/session/has_title_spec.rb +4 -2
- data/lib/capybara/spec/session/has_xpath_spec.rb +5 -3
- data/lib/capybara/spec/session/node_spec.rb +50 -26
- data/lib/capybara/spec/session/refresh_spec.rb +28 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +3 -2
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
- data/lib/capybara/spec/session/unselect_spec.rb +2 -2
- data/lib/capybara/spec/session/visit_spec.rb +56 -1
- data/lib/capybara/spec/session/window/become_closed_spec.rb +11 -11
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +11 -9
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -4
- data/lib/capybara/spec/session/window/within_window_spec.rb +27 -2
- data/lib/capybara/spec/spec_helper.rb +28 -4
- data/lib/capybara/spec/test_app.rb +3 -1
- data/lib/capybara/spec/views/form.erb +27 -1
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +5 -0
- data/lib/capybara/spec/views/with_html.erb +33 -2
- data/lib/capybara/spec/views/with_js.erb +12 -0
- data/lib/capybara/spec/views/with_windows.erb +4 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/lib/capybara.rb +102 -124
- data/spec/capybara_spec.rb +43 -21
- data/spec/dsl_spec.rb +1 -0
- data/spec/filter_set_spec.rb +28 -0
- data/spec/minitest_spec.rb +9 -1
- data/spec/minitest_spec_spec.rb +19 -5
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/result_spec.rb +20 -0
- data/spec/rspec/shared_spec_matchers.rb +148 -44
- data/spec/rspec/views_spec.rb +4 -0
- data/spec/rspec_matchers_spec.rb +46 -0
- data/spec/rspec_spec.rb +77 -0
- data/spec/selector_spec.rb +2 -1
- data/spec/selenium_spec_chrome.rb +25 -17
- data/spec/selenium_spec_firefox.rb +2 -1
- data/spec/selenium_spec_marionette.rb +18 -5
- data/spec/session_spec.rb +44 -0
- data/spec/shared_selenium_session.rb +72 -8
- data/spec/spec_helper.rb +4 -0
- metadata +55 -8
@@ -21,7 +21,7 @@ end
|
|
21
21
|
module Capybara
|
22
22
|
class Selector
|
23
23
|
|
24
|
-
attr_reader :name, :format
|
24
|
+
attr_reader :name, :format
|
25
25
|
|
26
26
|
class << self
|
27
27
|
def all
|
@@ -50,7 +50,7 @@ module Capybara
|
|
50
50
|
@description = nil
|
51
51
|
@format = nil
|
52
52
|
@expression = nil
|
53
|
-
@expression_filters =
|
53
|
+
@expression_filters = {}
|
54
54
|
@default_visibility = nil
|
55
55
|
instance_eval(&block)
|
56
56
|
end
|
@@ -59,6 +59,14 @@ module Capybara
|
|
59
59
|
@filter_set.filters
|
60
60
|
end
|
61
61
|
|
62
|
+
def node_filters
|
63
|
+
@filter_set.node_filters
|
64
|
+
end
|
65
|
+
|
66
|
+
def expression_filters
|
67
|
+
@filter_set.expression_filters
|
68
|
+
end
|
69
|
+
|
62
70
|
##
|
63
71
|
#
|
64
72
|
# Define a selector by an xpath expression
|
@@ -74,7 +82,10 @@ module Capybara
|
|
74
82
|
# @return [#call] The block that will be called to generate the XPath expression
|
75
83
|
#
|
76
84
|
def xpath(*expression_filters, &block)
|
77
|
-
|
85
|
+
if block
|
86
|
+
@format, @expression = :xpath, block
|
87
|
+
expression_filters.flatten.each { |ef| custom_filters[ef] = Filters::IdentityExpressionFilter.new }
|
88
|
+
end
|
78
89
|
format == :xpath ? @expression : nil
|
79
90
|
end
|
80
91
|
|
@@ -93,7 +104,10 @@ module Capybara
|
|
93
104
|
# @return [#call] The block that will be called to generate the CSS selector
|
94
105
|
#
|
95
106
|
def css(*expression_filters, &block)
|
96
|
-
|
107
|
+
if block
|
108
|
+
@format, @expression = :css, block
|
109
|
+
expression_filters.flatten.each { |ef| custom_filters[ef] = nil }
|
110
|
+
end
|
97
111
|
format == :css ? @expression : nil
|
98
112
|
end
|
99
113
|
|
@@ -172,8 +186,14 @@ module Capybara
|
|
172
186
|
#
|
173
187
|
def filter(name, *types_and_options, &block)
|
174
188
|
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
175
|
-
types_and_options.each { |k| options[k] = true}
|
176
|
-
custom_filters[name] =
|
189
|
+
types_and_options.each { |k| options[k] = true }
|
190
|
+
custom_filters[name] = Filters::NodeFilter.new(name, block, options)
|
191
|
+
end
|
192
|
+
|
193
|
+
def expression_filter(name, *types_and_options, &block)
|
194
|
+
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
195
|
+
types_and_options.each { |k| options[k] = true }
|
196
|
+
custom_filters[name] = Filters::ExpressionFilter.new(name, block, options)
|
177
197
|
end
|
178
198
|
|
179
199
|
def filter_set(name, filters_to_use = nil)
|
@@ -181,6 +201,7 @@ module Capybara
|
|
181
201
|
f_set.filters.each do |n, filter|
|
182
202
|
custom_filters[n] = filter if filters_to_use.nil? || filters_to_use.include?(n)
|
183
203
|
end
|
204
|
+
|
184
205
|
f_set.descriptions.each { |desc| @filter_set.describe(&desc) }
|
185
206
|
end
|
186
207
|
|
@@ -201,9 +222,9 @@ module Capybara
|
|
201
222
|
@default_visibility = default_visibility
|
202
223
|
end
|
203
224
|
|
204
|
-
def default_visibility
|
225
|
+
def default_visibility(fallback = Capybara.ignore_hidden_elements)
|
205
226
|
if @default_visibility.nil?
|
206
|
-
|
227
|
+
fallback
|
207
228
|
else
|
208
229
|
@default_visibility
|
209
230
|
end
|
@@ -215,17 +236,17 @@ module Capybara
|
|
215
236
|
locate_xpath = xpath #need to save original xpath for the label wrap
|
216
237
|
if locator
|
217
238
|
locator = locator.to_s
|
218
|
-
attr_matchers = XPath.attr(:id).equals(locator)
|
219
|
-
XPath.attr(:name).equals(locator)
|
220
|
-
XPath.attr(:placeholder).equals(locator)
|
221
|
-
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for))
|
222
|
-
attr_matchers
|
239
|
+
attr_matchers = XPath.attr(:id).equals(locator).or(
|
240
|
+
XPath.attr(:name).equals(locator)).or(
|
241
|
+
XPath.attr(:placeholder).equals(locator)).or(
|
242
|
+
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)))
|
243
|
+
attr_matchers = attr_matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
223
244
|
|
224
245
|
locate_xpath = locate_xpath[attr_matchers]
|
225
|
-
locate_xpath
|
246
|
+
locate_xpath = locate_xpath.union(XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath))
|
226
247
|
end
|
227
248
|
|
228
|
-
locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
249
|
+
# locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
229
250
|
locate_xpath
|
230
251
|
end
|
231
252
|
|
data/lib/capybara/selector.rb
CHANGED
@@ -6,11 +6,15 @@ Capybara::Selector::FilterSet.add(:_field) do
|
|
6
6
|
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
|
7
7
|
filter(:multiple, :boolean) { |node, value| !(value ^ node.multiple?) }
|
8
8
|
|
9
|
+
expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name).equals(val)] }
|
10
|
+
expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder).equals(val)] }
|
11
|
+
|
9
12
|
describe do |options|
|
10
13
|
desc, states = String.new, []
|
11
14
|
states << 'checked' if options[:checked] || (options[:unchecked] == false)
|
12
15
|
states << 'not checked' if options[:unchecked] || (options[:checked] == false)
|
13
16
|
states << 'disabled' if options[:disabled] == true
|
17
|
+
states << 'not disabled' if options[:disabled] == false
|
14
18
|
desc << " that is #{states.join(' and ')}" unless states.empty?
|
15
19
|
desc << " with the multiple attribute" if options[:multiple] == true
|
16
20
|
desc << " without the multiple attribute" if options[:multiple] == false
|
@@ -65,21 +69,21 @@ end
|
|
65
69
|
# @filter [Boolean] :disabled Match disabled field?
|
66
70
|
# @filter [Boolean] :multiple Match fields that accept multiple values
|
67
71
|
Capybara.add_selector(:field) do
|
68
|
-
xpath
|
72
|
+
xpath do |locator, options|
|
69
73
|
xpath = XPath.descendant(:input, :textarea, :select)[~XPath.attr(:type).one_of('submit', 'image', 'hidden')]
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
locate_field(xpath, locator, options)
|
75
|
+
end
|
76
|
+
|
77
|
+
expression_filter(:type) do |expr, type|
|
78
|
+
type = type.to_s
|
79
|
+
if ['textarea', 'select'].include?(type)
|
80
|
+
expr.axis(:self, type.to_sym)
|
81
|
+
else
|
82
|
+
expr[XPath.attr(:type).equals(type)]
|
77
83
|
end
|
78
|
-
xpath=locate_field(xpath, locator, options)
|
79
|
-
xpath
|
80
84
|
end
|
81
85
|
|
82
|
-
filter_set(:_field) # checked/unchecked/disabled/multiple
|
86
|
+
filter_set(:_field) # checked/unchecked/disabled/multiple/name/placeholder
|
83
87
|
|
84
88
|
filter(:readonly, :boolean) { |node, value| not(value ^ node.readonly?) }
|
85
89
|
filter(:with) do |node, with|
|
@@ -87,7 +91,7 @@ Capybara.add_selector(:field) do
|
|
87
91
|
end
|
88
92
|
describe do |options|
|
89
93
|
desc = String.new
|
90
|
-
(expression_filters - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.has_key?(ef) }
|
94
|
+
(expression_filters.keys - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.has_key?(ef) }
|
91
95
|
desc << " of type #{options[:type].inspect}" if options[:type]
|
92
96
|
desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
|
93
97
|
desc
|
@@ -107,7 +111,7 @@ end
|
|
107
111
|
Capybara.add_selector(:fieldset) do
|
108
112
|
xpath(:legend) do |locator, options|
|
109
113
|
xpath = XPath.descendant(:fieldset)
|
110
|
-
xpath = xpath[XPath.attr(:id).equals(locator.to_s)
|
114
|
+
xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.child(:legend)[XPath.string.n.is(locator.to_s)]] unless locator.nil?
|
111
115
|
xpath = xpath[XPath.child(:legend)[XPath.string.n.is(options[:legend])]] if options[:legend]
|
112
116
|
xpath
|
113
117
|
end
|
@@ -135,11 +139,11 @@ Capybara.add_selector(:link) do
|
|
135
139
|
end
|
136
140
|
unless locator.nil?
|
137
141
|
locator = locator.to_s
|
138
|
-
matchers = XPath.attr(:id).equals(locator)
|
139
|
-
XPath.string.n.is(locator)
|
140
|
-
XPath.attr(:title).is(locator)
|
141
|
-
XPath.descendant(:img)[XPath.attr(:alt).is(locator)]
|
142
|
-
matchers
|
142
|
+
matchers = XPath.attr(:id).equals(locator).or(
|
143
|
+
XPath.string.n.is(locator)).or(
|
144
|
+
XPath.attr(:title).is(locator)).or(
|
145
|
+
XPath.descendant(:img)[XPath.attr(:alt).is(locator)])
|
146
|
+
matchers = matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
143
147
|
xpath = xpath[matchers]
|
144
148
|
end
|
145
149
|
xpath = [:title].inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
@@ -184,21 +188,21 @@ Capybara.add_selector(:button) do
|
|
184
188
|
|
185
189
|
unless locator.nil?
|
186
190
|
locator = locator.to_s
|
187
|
-
locator_matches = XPath.attr(:id).equals(locator)
|
188
|
-
locator_matches
|
191
|
+
locator_matches = XPath.attr(:id).equals(locator).or XPath.attr(:value).is(locator).or XPath.attr(:title).is(locator)
|
192
|
+
locator_matches = locator_matches.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
189
193
|
|
190
194
|
input_btn_xpath = input_btn_xpath[locator_matches]
|
191
195
|
|
192
|
-
btn_xpath = btn_xpath[locator_matches
|
196
|
+
btn_xpath = btn_xpath[locator_matches.or XPath.string.n.is(locator).or XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
|
193
197
|
|
194
198
|
alt_matches = XPath.attr(:alt).is(locator)
|
195
|
-
alt_matches
|
199
|
+
alt_matches = alt_matches.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
196
200
|
image_btn_xpath = image_btn_xpath[alt_matches]
|
197
201
|
end
|
198
202
|
|
199
|
-
res_xpath = input_btn_xpath
|
203
|
+
res_xpath = input_btn_xpath.union(btn_xpath).union(image_btn_xpath)
|
200
204
|
|
201
|
-
res_xpath = expression_filters.inject(res_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
205
|
+
res_xpath = expression_filters.keys.inject(res_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
202
206
|
|
203
207
|
res_xpath
|
204
208
|
end
|
@@ -220,7 +224,7 @@ end
|
|
220
224
|
Capybara.add_selector(:link_or_button) do
|
221
225
|
label "link or button"
|
222
226
|
xpath do |locator, options|
|
223
|
-
self.class.all.values_at(:link, :button).map {|selector| selector.xpath.call(locator, options)}.reduce(
|
227
|
+
self.class.all.values_at(:link, :button).map {|selector| selector.xpath.call(locator, options)}.reduce(:union)
|
224
228
|
end
|
225
229
|
|
226
230
|
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
|
@@ -237,18 +241,28 @@ end
|
|
237
241
|
# @filter [String] :name Matches the name attribute
|
238
242
|
# @filter [String] :placeholder Matches the placeholder attribute
|
239
243
|
# @filter [String] :with Matches the current value of the field
|
244
|
+
# @filter [String] :type Matches the type attribute of the field or element type for 'textarea'
|
240
245
|
# @filter [String, Array<String>] :class Matches the class(es) provided
|
241
246
|
# @filter [Boolean] :disabled Match disabled field?
|
242
247
|
# @filter [Boolean] :multiple Match fields that accept multiple values
|
243
248
|
#
|
244
249
|
Capybara.add_selector(:fillable_field) do
|
245
250
|
label "field"
|
246
|
-
xpath
|
251
|
+
xpath do |locator, options|
|
247
252
|
xpath = XPath.descendant(:input, :textarea)[~XPath.attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
|
248
253
|
locate_field(xpath, locator, options)
|
249
254
|
end
|
250
255
|
|
251
|
-
|
256
|
+
expression_filter(:type) do |expr, type|
|
257
|
+
type = type.to_s
|
258
|
+
if ['textarea'].include?(type)
|
259
|
+
expr.axis(:self, type.to_sym)
|
260
|
+
else
|
261
|
+
expr[XPath.attr(:type).equals(type)]
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
filter_set(:_field, [:disabled, :multiple, :name, :placeholder])
|
252
266
|
|
253
267
|
filter(:with) do |node, with|
|
254
268
|
with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
|
@@ -277,12 +291,12 @@ end
|
|
277
291
|
#
|
278
292
|
Capybara.add_selector(:radio_button) do
|
279
293
|
label "radio button"
|
280
|
-
xpath
|
294
|
+
xpath do |locator, options|
|
281
295
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('radio')]
|
282
296
|
locate_field(xpath, locator, options)
|
283
297
|
end
|
284
298
|
|
285
|
-
filter_set(:_field, [:checked, :unchecked, :disabled])
|
299
|
+
filter_set(:_field, [:checked, :unchecked, :disabled, :name])
|
286
300
|
|
287
301
|
filter(:option) { |node, value| node.value == value.to_s }
|
288
302
|
|
@@ -308,12 +322,12 @@ end
|
|
308
322
|
# @filter [String] :option Match the value
|
309
323
|
#
|
310
324
|
Capybara.add_selector(:checkbox) do
|
311
|
-
xpath
|
325
|
+
xpath do |locator, options|
|
312
326
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('checkbox')]
|
313
327
|
locate_field(xpath, locator, options)
|
314
328
|
end
|
315
329
|
|
316
|
-
filter_set(:_field, [:checked, :unchecked, :disabled])
|
330
|
+
filter_set(:_field, [:checked, :unchecked, :disabled, :name])
|
317
331
|
|
318
332
|
filter(:option) { |node, value| node.value == value.to_s }
|
319
333
|
|
@@ -339,15 +353,16 @@ end
|
|
339
353
|
# @filter [Array<String>] :options Exact match options
|
340
354
|
# @filter [Array<String>] :with_options Partial match options
|
341
355
|
# @filter [String, Array<String>] :selected Match the selection(s)
|
356
|
+
# @filter [String, Array<String>] :with_selected Partial match the selection(s)
|
342
357
|
#
|
343
358
|
Capybara.add_selector(:select) do
|
344
359
|
label "select box"
|
345
|
-
xpath
|
360
|
+
xpath do |locator, options|
|
346
361
|
xpath = XPath.descendant(:select)
|
347
362
|
locate_field(xpath, locator, options)
|
348
363
|
end
|
349
364
|
|
350
|
-
filter_set(:_field, [:disabled, :multiple])
|
365
|
+
filter_set(:_field, [:disabled, :multiple, :name, :placeholder])
|
351
366
|
|
352
367
|
filter(:options) do |node, options|
|
353
368
|
if node.visible?
|
@@ -367,8 +382,13 @@ Capybara.add_selector(:select) do
|
|
367
382
|
end
|
368
383
|
|
369
384
|
filter(:selected) do |node, selected|
|
370
|
-
actual = node.all(:xpath, './/option', visible: false).select
|
371
|
-
|
385
|
+
actual = node.all(:xpath, './/option', visible: false).select(&:selected?).map { |option| option.text(:all) }
|
386
|
+
Array(selected).sort == actual.sort
|
387
|
+
end
|
388
|
+
|
389
|
+
filter(:with_selected) do |node, selected|
|
390
|
+
actual = node.all(:xpath, './/option', visible: false).select(&:selected?).map { |option| option.text(:all) }
|
391
|
+
(Array(selected) - actual).empty?
|
372
392
|
end
|
373
393
|
|
374
394
|
describe do |options|
|
@@ -376,6 +396,7 @@ Capybara.add_selector(:select) do
|
|
376
396
|
desc << " with options #{options[:options].inspect}" if options[:options]
|
377
397
|
desc << " with at least options #{options[:with_options].inspect}" if options[:with_options]
|
378
398
|
desc << " with #{options[:selected].inspect} selected" if options[:selected]
|
399
|
+
desc << " with at least #{options[:with_selected].inspect} selected" if options[:with_selected]
|
379
400
|
desc << describe_all_expression_filters(options)
|
380
401
|
desc
|
381
402
|
end
|
@@ -420,12 +441,12 @@ end
|
|
420
441
|
#
|
421
442
|
Capybara.add_selector(:file_field) do
|
422
443
|
label "file field"
|
423
|
-
xpath
|
444
|
+
xpath do |locator, options|
|
424
445
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('file')]
|
425
446
|
locate_field(xpath, locator, options)
|
426
447
|
end
|
427
448
|
|
428
|
-
filter_set(:_field, [:disabled, :multiple])
|
449
|
+
filter_set(:_field, [:disabled, :multiple, :name])
|
429
450
|
|
430
451
|
describe do |options|
|
431
452
|
desc = String.new
|
@@ -445,7 +466,7 @@ Capybara.add_selector(:label) do
|
|
445
466
|
label "label"
|
446
467
|
xpath(:for) do |locator, options|
|
447
468
|
xpath = XPath.descendant(:label)
|
448
|
-
xpath = xpath[XPath.string.n.is(locator.to_s)
|
469
|
+
xpath = xpath[XPath.string.n.is(locator.to_s).or XPath.attr(:id).equals(locator.to_s)] unless locator.nil?
|
449
470
|
if options.has_key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
|
450
471
|
xpath = xpath[XPath.attr(:for).equals(options[:for].to_s).or((~XPath.attr(:for)).and(XPath.descendant()[XPath.attr(:id).equals(options[:for].to_s)]))]
|
451
472
|
end
|
@@ -484,7 +505,7 @@ end
|
|
484
505
|
Capybara.add_selector(:table) do
|
485
506
|
xpath(:caption) do |locator, options|
|
486
507
|
xpath = XPath.descendant(:table)
|
487
|
-
xpath = xpath[XPath.attr(:id).equals(locator.to_s)
|
508
|
+
xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.descendant(:caption).is(locator.to_s)] unless locator.nil?
|
488
509
|
xpath = xpath[XPath.descendant(:caption).equals(options[:caption])] if options[:caption]
|
489
510
|
xpath
|
490
511
|
end
|
@@ -507,9 +528,9 @@ end
|
|
507
528
|
#
|
508
529
|
Capybara.add_selector(:frame) do
|
509
530
|
xpath(:name) do |locator, options|
|
510
|
-
xpath = XPath.descendant(:iframe)
|
511
|
-
xpath = xpath[XPath.attr(:id).equals(locator.to_s)
|
512
|
-
xpath = expression_filters.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
531
|
+
xpath = XPath.descendant(:iframe).union(XPath.descendant(:frame))
|
532
|
+
xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.attr(:name).equals(locator)] unless locator.nil?
|
533
|
+
xpath = expression_filters.keys.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
513
534
|
xpath
|
514
535
|
end
|
515
536
|
|