capybara 3.3.1 → 3.4.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 +4 -4
- data/History.md +16 -0
- data/README.md +5 -7
- data/lib/capybara.rb +7 -6
- data/lib/capybara/config.rb +1 -1
- data/lib/capybara/dsl.rb +2 -2
- data/lib/capybara/helpers.rb +3 -3
- data/lib/capybara/minitest/spec.rb +3 -3
- data/lib/capybara/node/actions.rb +18 -18
- data/lib/capybara/node/base.rb +1 -1
- data/lib/capybara/node/element.rb +2 -2
- data/lib/capybara/node/finders.rb +6 -6
- data/lib/capybara/node/matchers.rb +5 -5
- data/lib/capybara/node/simple.rb +2 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +12 -11
- data/lib/capybara/queries/current_path_query.rb +1 -1
- data/lib/capybara/queries/selector_query.rb +39 -15
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +1 -1
- data/lib/capybara/rack_test/browser.rb +7 -7
- data/lib/capybara/rack_test/driver.rb +1 -1
- data/lib/capybara/rack_test/form.rb +7 -7
- data/lib/capybara/rack_test/node.rb +16 -16
- data/lib/capybara/rails.rb +1 -1
- data/lib/capybara/result.rb +8 -4
- data/lib/capybara/rspec/features.rb +4 -4
- data/lib/capybara/rspec/matchers.rb +6 -6
- data/lib/capybara/selector.rb +106 -90
- data/lib/capybara/selector/css.rb +4 -4
- data/lib/capybara/selector/filter_set.rb +52 -8
- data/lib/capybara/selector/selector.rb +39 -15
- data/lib/capybara/selenium/driver.rb +10 -10
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +8 -0
- data/lib/capybara/selenium/node.rb +9 -10
- data/lib/capybara/selenium/nodes/chrome_node.rb +18 -0
- data/lib/capybara/selenium/nodes/marionette_node.rb +32 -7
- data/lib/capybara/server.rb +3 -3
- data/lib/capybara/server/animation_disabler.rb +1 -1
- data/lib/capybara/server/middleware.rb +1 -1
- data/lib/capybara/session.rb +23 -19
- data/lib/capybara/session/config.rb +18 -3
- data/lib/capybara/spec/public/test.js +1 -1
- data/lib/capybara/spec/session/accept_alert_spec.rb +10 -10
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
- data/lib/capybara/spec/session/all_spec.rb +33 -32
- data/lib/capybara/spec/session/ancestor_spec.rb +19 -19
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +38 -38
- data/lib/capybara/spec/session/assert_current_path_spec.rb +16 -16
- data/lib/capybara/spec/session/assert_selector_spec.rb +53 -53
- data/lib/capybara/spec/session/assert_style_spec.rb +3 -3
- data/lib/capybara/spec/session/assert_text_spec.rb +31 -30
- data/lib/capybara/spec/session/assert_title_spec.rb +12 -12
- data/lib/capybara/spec/session/attach_file_spec.rb +51 -52
- data/lib/capybara/spec/session/body_spec.rb +6 -6
- data/lib/capybara/spec/session/check_spec.rb +52 -47
- data/lib/capybara/spec/session/choose_spec.rb +32 -32
- data/lib/capybara/spec/session/click_button_spec.rb +103 -103
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +24 -23
- data/lib/capybara/spec/session/click_link_spec.rb +49 -48
- data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
- data/lib/capybara/spec/session/current_url_spec.rb +26 -27
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
- data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +8 -8
- data/lib/capybara/spec/session/element/match_css_spec.rb +10 -10
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +51 -51
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
- data/lib/capybara/spec/session/evaluate_script_spec.rb +15 -8
- data/lib/capybara/spec/session/execute_script_spec.rb +7 -7
- data/lib/capybara/spec/session/fill_in_spec.rb +43 -42
- data/lib/capybara/spec/session/find_button_spec.rb +23 -23
- data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
- data/lib/capybara/spec/session/find_field_spec.rb +32 -30
- data/lib/capybara/spec/session/find_link_spec.rb +21 -21
- data/lib/capybara/spec/session/find_spec.rb +153 -135
- data/lib/capybara/spec/session/first_spec.rb +41 -41
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +17 -17
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +31 -17
- data/lib/capybara/spec/session/go_back_spec.rb +1 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +17 -17
- data/lib/capybara/spec/session/has_button_spec.rb +13 -13
- data/lib/capybara/spec/session/has_css_spec.rb +133 -131
- data/lib/capybara/spec/session/has_current_path_spec.rb +29 -29
- data/lib/capybara/spec/session/has_field_spec.rb +58 -58
- data/lib/capybara/spec/session/has_link_spec.rb +4 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +24 -24
- data/lib/capybara/spec/session/has_select_spec.rb +43 -43
- data/lib/capybara/spec/session/has_selector_spec.rb +71 -71
- data/lib/capybara/spec/session/has_style_spec.rb +3 -3
- data/lib/capybara/spec/session/has_table_spec.rb +4 -4
- data/lib/capybara/spec/session/has_text_spec.rb +53 -52
- data/lib/capybara/spec/session/has_title_spec.rb +14 -14
- data/lib/capybara/spec/session/has_xpath_spec.rb +39 -38
- data/lib/capybara/spec/session/headers_spec.rb +1 -1
- data/lib/capybara/spec/session/html_spec.rb +6 -6
- data/lib/capybara/spec/session/node_spec.rb +129 -123
- data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
- data/lib/capybara/spec/session/refresh_spec.rb +4 -7
- data/lib/capybara/spec/session/reset_session_spec.rb +28 -28
- data/lib/capybara/spec/session/response_code_spec.rb +1 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +37 -37
- data/lib/capybara/spec/session/save_screenshot_spec.rb +6 -6
- data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/select_spec.rb +81 -81
- data/lib/capybara/spec/session/selectors_spec.rb +17 -17
- data/lib/capybara/spec/session/sibling_spec.rb +9 -9
- data/lib/capybara/spec/session/text_spec.rb +23 -23
- data/lib/capybara/spec/session/title_spec.rb +5 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +24 -20
- data/lib/capybara/spec/session/unselect_spec.rb +37 -37
- data/lib/capybara/spec/session/visit_spec.rb +48 -49
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -16
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -2
- data/lib/capybara/spec/session/window/window_spec.rb +4 -4
- data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
- data/lib/capybara/spec/session/within_spec.rb +41 -41
- data/lib/capybara/spec/spec_helper.rb +11 -9
- data/lib/capybara/spec/test_app.rb +18 -17
- data/lib/capybara/spec/views/form.erb +29 -31
- data/lib/capybara/spec/views/with_html.erb +2 -2
- data/lib/capybara/version.rb +1 -1
- data/spec/basic_node_spec.rb +23 -23
- data/spec/capybara_spec.rb +20 -20
- data/spec/css_splitter_spec.rb +7 -7
- data/spec/dsl_spec.rb +37 -32
- data/spec/filter_set_spec.rb +4 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +4 -4
- data/spec/minitest_spec_spec.rb +23 -23
- data/spec/per_session_config_spec.rb +5 -5
- data/spec/rack_test_spec.rb +44 -44
- data/spec/result_spec.rb +14 -14
- data/spec/rspec/features_spec.rb +13 -13
- data/spec/rspec/scenarios_spec.rb +4 -4
- data/spec/rspec/shared_spec_matchers.rb +282 -281
- data/spec/rspec/views_spec.rb +3 -3
- data/spec/rspec_matchers_spec.rb +10 -10
- data/spec/rspec_spec.rb +29 -29
- data/spec/selector_spec.rb +64 -64
- data/spec/selenium_spec_chrome.rb +14 -22
- data/spec/selenium_spec_chrome_remote.rb +28 -8
- data/spec/selenium_spec_edge.rb +9 -4
- data/spec/selenium_spec_firefox_remote.rb +87 -0
- data/spec/selenium_spec_ie.rb +9 -4
- data/spec/selenium_spec_marionette.rb +42 -18
- data/spec/server_spec.rb +29 -27
- data/spec/session_spec.rb +17 -17
- data/spec/shared_selenium_session.rb +70 -52
- data/spec/spec_helper.rb +1 -1
- metadata +4 -2
data/lib/capybara/selector.rb
CHANGED
@@ -10,15 +10,15 @@ Capybara::Selector::FilterSet.add(:_field) do
|
|
10
10
|
expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name) == val] }
|
11
11
|
expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder) == val] }
|
12
12
|
|
13
|
-
describe do |checked: nil, unchecked: nil, disabled: nil, multiple: nil,
|
14
|
-
desc, states = +
|
13
|
+
describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, multiple: nil, **|
|
14
|
+
desc, states = +'', []
|
15
15
|
states << 'checked' if checked || (unchecked == false)
|
16
16
|
states << 'not checked' if unchecked || (checked == false)
|
17
17
|
states << 'disabled' if disabled == true
|
18
18
|
states << 'not disabled' if disabled == false
|
19
19
|
desc << " that is #{states.join(' and ')}" unless states.empty?
|
20
|
-
desc <<
|
21
|
-
desc <<
|
20
|
+
desc << ' with the multiple attribute' if multiple == true
|
21
|
+
desc << ' without the multiple attribute' if multiple == false
|
22
22
|
desc
|
23
23
|
end
|
24
24
|
end
|
@@ -58,26 +58,34 @@ Capybara.add_selector(:field) do
|
|
58
58
|
node_filter(:with) do |node, with|
|
59
59
|
with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
|
60
60
|
end
|
61
|
-
|
62
|
-
|
61
|
+
|
62
|
+
describe_expression_filters do |type: nil, **options|
|
63
|
+
desc = +''
|
63
64
|
(expression_filters.keys - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.key?(ef) }
|
64
65
|
desc << " of type #{type.inspect}" if type
|
65
|
-
desc << " with value #{options[:with].to_s.inspect}" if options.key?(:with)
|
66
66
|
desc
|
67
67
|
end
|
68
|
+
|
69
|
+
describe_node_filters do |**options|
|
70
|
+
" with value #{options[:with].to_s.inspect}" if options.key?(:with)
|
71
|
+
end
|
68
72
|
end
|
69
73
|
|
70
74
|
Capybara.add_selector(:fieldset) do
|
71
|
-
xpath(:legend) do |locator, legend: nil,
|
75
|
+
xpath(:legend) do |locator, legend: nil, **|
|
76
|
+
locator_matchers = (XPath.attr(:id) == locator.to_s) | XPath.child(:legend)[XPath.string.n.is(locator.to_s)]
|
77
|
+
locator_matchers |= XPath.attr(test_id) == locator if test_id
|
72
78
|
xpath = XPath.descendant(:fieldset)
|
73
|
-
xpath = xpath[
|
79
|
+
xpath = xpath[locator_matchers] unless locator.nil?
|
74
80
|
xpath = xpath[XPath.child(:legend)[XPath.string.n.is(legend)]] if legend
|
75
81
|
xpath
|
76
82
|
end
|
83
|
+
|
84
|
+
node_filter(:disabled, :boolean) { |node, value| !(value ^ node.disabled?) }
|
77
85
|
end
|
78
86
|
|
79
87
|
Capybara.add_selector(:link) do
|
80
|
-
xpath(:title, :alt) do |locator, href: true,
|
88
|
+
xpath(:title, :alt) do |locator, href: true, alt: nil, title: nil, **|
|
81
89
|
xpath = XPath.descendant(:a)
|
82
90
|
xpath = xpath[
|
83
91
|
case href
|
@@ -99,6 +107,7 @@ Capybara.add_selector(:link) do
|
|
99
107
|
XPath.attr(:title).is(locator),
|
100
108
|
XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
|
101
109
|
matchers << XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
110
|
+
matchers << XPath.attr(test_id) == locator if test_id
|
102
111
|
xpath = xpath[matchers.reduce(:|)]
|
103
112
|
end
|
104
113
|
|
@@ -121,27 +130,33 @@ Capybara.add_selector(:link) do
|
|
121
130
|
expr[mod]
|
122
131
|
end
|
123
132
|
|
124
|
-
|
125
|
-
desc = +
|
126
|
-
desc << " with href #{options[:href].inspect}" if options[:href]
|
127
|
-
desc <<
|
133
|
+
describe_expression_filters do |**options|
|
134
|
+
desc = +''
|
135
|
+
desc << " with href #{options[:href].inspect}" if options[:href] && !options[:href].is_a?(Regexp)
|
136
|
+
desc << ' with no href attribute' if options.fetch(:href, true).nil?
|
137
|
+
desc
|
138
|
+
end
|
139
|
+
|
140
|
+
describe_node_filters do |href: nil, **|
|
141
|
+
" with href matching #{href.inspect}" if href.is_a? Regexp
|
128
142
|
end
|
129
143
|
end
|
130
144
|
|
131
145
|
Capybara.add_selector(:button) do
|
132
|
-
xpath(:value, :title, :type) do |locator,
|
146
|
+
xpath(:value, :title, :type) do |locator, **options|
|
133
147
|
input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
|
134
148
|
btn_xpath = XPath.descendant(:button)
|
135
149
|
image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type) == 'image']
|
136
150
|
|
137
151
|
unless locator.nil?
|
138
152
|
locator = locator.to_s
|
139
|
-
|
140
|
-
|
153
|
+
locator_matchers = XPath.attr(:id).equals(locator) | XPath.attr(:value).is(locator) | XPath.attr(:title).is(locator)
|
154
|
+
locator_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
155
|
+
locator_matchers |= XPath.attr(test_id) == locator if test_id
|
141
156
|
|
142
|
-
input_btn_xpath = input_btn_xpath[
|
157
|
+
input_btn_xpath = input_btn_xpath[locator_matchers]
|
143
158
|
|
144
|
-
btn_xpath = btn_xpath[
|
159
|
+
btn_xpath = btn_xpath[locator_matchers | XPath.string.n.is(locator) | XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
|
145
160
|
|
146
161
|
alt_matches = XPath.attr(:alt).is(locator)
|
147
162
|
alt_matches |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
@@ -157,27 +172,27 @@ Capybara.add_selector(:button) do
|
|
157
172
|
|
158
173
|
node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) }
|
159
174
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
desc << describe_all_expression_filters(options)
|
164
|
-
desc
|
175
|
+
describe_expression_filters
|
176
|
+
describe_node_filters do |disabled: nil, **|
|
177
|
+
' that is disabled' if disabled == true
|
165
178
|
end
|
166
179
|
end
|
167
180
|
|
168
181
|
Capybara.add_selector(:link_or_button) do
|
169
|
-
label
|
182
|
+
label 'link or button'
|
170
183
|
xpath do |locator, **options|
|
171
184
|
self.class.all.values_at(:link, :button).map { |selector| selector.xpath.call(locator, options) }.reduce(:union)
|
172
185
|
end
|
173
186
|
|
174
|
-
node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name ==
|
187
|
+
node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == 'a' || !(value ^ node.disabled?) }
|
175
188
|
|
176
|
-
|
189
|
+
describe_node_filters do |disabled: nil, **|
|
190
|
+
' that is disabled' if disabled == true
|
191
|
+
end
|
177
192
|
end
|
178
193
|
|
179
194
|
Capybara.add_selector(:fillable_field) do
|
180
|
-
label
|
195
|
+
label 'field'
|
181
196
|
|
182
197
|
xpath do |locator, **options|
|
183
198
|
xpath = XPath.descendant(:input, :textarea)[!XPath.attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
|
@@ -186,7 +201,7 @@ Capybara.add_selector(:fillable_field) do
|
|
186
201
|
|
187
202
|
expression_filter(:type) do |expr, type|
|
188
203
|
type = type.to_s
|
189
|
-
if
|
204
|
+
if type == 'textarea'
|
190
205
|
expr.self(type.to_sym)
|
191
206
|
else
|
192
207
|
expr[XPath.attr(:type) == type]
|
@@ -199,16 +214,14 @@ Capybara.add_selector(:fillable_field) do
|
|
199
214
|
with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
|
200
215
|
end
|
201
216
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
desc << " with value #{options[:with].to_s.inspect}" if options.key?(:with)
|
206
|
-
desc
|
217
|
+
describe_expression_filters
|
218
|
+
describe_node_filters do |**options|
|
219
|
+
" with value #{options[:with].to_s.inspect}" if options.key?(:with)
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
223
|
Capybara.add_selector(:radio_button) do
|
211
|
-
label
|
224
|
+
label 'radio button'
|
212
225
|
|
213
226
|
xpath do |locator, **options|
|
214
227
|
xpath = XPath.descendant(:input)[XPath.attr(:type) == 'radio']
|
@@ -219,11 +232,9 @@ Capybara.add_selector(:radio_button) do
|
|
219
232
|
|
220
233
|
node_filter(:option) { |node, value| node.value == value.to_s }
|
221
234
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
desc << describe_all_expression_filters(options)
|
226
|
-
desc
|
235
|
+
describe_expression_filters
|
236
|
+
describe_node_filters do |option: nil, **|
|
237
|
+
" with value #{option.inspect}" if option
|
227
238
|
end
|
228
239
|
end
|
229
240
|
|
@@ -237,16 +248,14 @@ Capybara.add_selector(:checkbox) do
|
|
237
248
|
|
238
249
|
node_filter(:option) { |node, value| node.value == value.to_s }
|
239
250
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
desc << describe_all_expression_filters(options)
|
244
|
-
desc
|
251
|
+
describe_expression_filters
|
252
|
+
describe_node_filters do |option: nil, **|
|
253
|
+
" with value #{option.inspect}" if option
|
245
254
|
end
|
246
255
|
end
|
247
256
|
|
248
257
|
Capybara.add_selector(:select) do
|
249
|
-
label
|
258
|
+
label 'select box'
|
250
259
|
|
251
260
|
xpath do |locator, **options|
|
252
261
|
xpath = XPath.descendant(:select)
|
@@ -280,19 +289,24 @@ Capybara.add_selector(:select) do
|
|
280
289
|
(Array(selected) - actual).empty?
|
281
290
|
end
|
282
291
|
|
283
|
-
|
284
|
-
desc = +
|
285
|
-
desc << " with options #{options.inspect}" if options
|
292
|
+
describe_expression_filters do |with_options: nil, **opts|
|
293
|
+
desc = +''
|
286
294
|
desc << " with at least options #{with_options.inspect}" if with_options
|
295
|
+
desc << describe_all_expression_filters(opts)
|
296
|
+
desc
|
297
|
+
end
|
298
|
+
|
299
|
+
describe_node_filters do |options: nil, selected: nil, with_selected: nil, **|
|
300
|
+
desc = +''
|
301
|
+
desc << " with options #{options.inspect}" if options
|
287
302
|
desc << " with #{selected.inspect} selected" if selected
|
288
303
|
desc << " with at least #{with_selected.inspect} selected" if with_selected
|
289
|
-
desc << describe_all_expression_filters(opts)
|
290
304
|
desc
|
291
305
|
end
|
292
306
|
end
|
293
307
|
|
294
308
|
Capybara.add_selector(:datalist_input) do
|
295
|
-
label
|
309
|
+
label 'input box with datalist completion'
|
296
310
|
|
297
311
|
xpath do |locator, **options|
|
298
312
|
xpath = XPath.descendant(:input)[XPath.attr(:list)]
|
@@ -312,13 +326,16 @@ Capybara.add_selector(:datalist_input) do
|
|
312
326
|
end
|
313
327
|
end
|
314
328
|
|
315
|
-
|
316
|
-
desc = +
|
317
|
-
desc << " with options #{options.inspect}" if options
|
329
|
+
describe_expression_filters do |with_options: nil, **opts|
|
330
|
+
desc = +''
|
318
331
|
desc << " with at least options #{with_options.inspect}" if with_options
|
319
332
|
desc << describe_all_expression_filters(opts)
|
320
333
|
desc
|
321
334
|
end
|
335
|
+
|
336
|
+
describe_node_filters do |options: nil, **|
|
337
|
+
" with options #{options.inspect}" if options
|
338
|
+
end
|
322
339
|
end
|
323
340
|
|
324
341
|
Capybara.add_selector(:option) do
|
@@ -331,8 +348,8 @@ Capybara.add_selector(:option) do
|
|
331
348
|
node_filter(:disabled, :boolean) { |node, value| !(value ^ node.disabled?) }
|
332
349
|
node_filter(:selected, :boolean) { |node, value| !(value ^ node.selected?) }
|
333
350
|
|
334
|
-
|
335
|
-
desc = +
|
351
|
+
describe_node_filters do |**options|
|
352
|
+
desc = +''
|
336
353
|
desc << " that is#{' not' unless options[:disabled]} disabled" if options.key?(:disabled)
|
337
354
|
desc << " that is#{' not' unless options[:selected]} selected" if options.key?(:selected)
|
338
355
|
desc
|
@@ -340,7 +357,7 @@ Capybara.add_selector(:option) do
|
|
340
357
|
end
|
341
358
|
|
342
359
|
Capybara.add_selector(:datalist_option) do
|
343
|
-
label
|
360
|
+
label 'datalist option'
|
344
361
|
visible(:all)
|
345
362
|
|
346
363
|
xpath do |locator|
|
@@ -351,15 +368,13 @@ Capybara.add_selector(:datalist_option) do
|
|
351
368
|
|
352
369
|
node_filter(:disabled, :boolean) { |node, value| !(value ^ node.disabled?) }
|
353
370
|
|
354
|
-
|
355
|
-
|
356
|
-
desc << " that is#{' not' unless options[:disabled]} disabled" if options.key?(:disabled)
|
357
|
-
desc
|
371
|
+
describe_node_filters do |**options|
|
372
|
+
" that is#{' not' unless options[:disabled]} disabled" if options.key?(:disabled)
|
358
373
|
end
|
359
374
|
end
|
360
375
|
|
361
376
|
Capybara.add_selector(:file_field) do
|
362
|
-
label
|
377
|
+
label 'file field'
|
363
378
|
xpath do |locator, options|
|
364
379
|
xpath = XPath.descendant(:input)[XPath.attr(:type) == 'file']
|
365
380
|
locate_field(xpath, locator, options)
|
@@ -367,18 +382,18 @@ Capybara.add_selector(:file_field) do
|
|
367
382
|
|
368
383
|
filter_set(:_field, %i[disabled multiple name])
|
369
384
|
|
370
|
-
|
371
|
-
desc = +""
|
372
|
-
desc << describe_all_expression_filters(options)
|
373
|
-
desc
|
374
|
-
end
|
385
|
+
describe_expression_filters
|
375
386
|
end
|
376
387
|
|
377
388
|
Capybara.add_selector(:label) do
|
378
|
-
label
|
389
|
+
label 'label'
|
379
390
|
xpath(:for) do |locator, options|
|
380
391
|
xpath = XPath.descendant(:label)
|
381
|
-
|
392
|
+
unless locator.nil?
|
393
|
+
locator_matchers = XPath.string.n.is(locator.to_s) | (XPath.attr(:id) == locator.to_s)
|
394
|
+
locator_matchers |= XPath.attr(test_id) == locator if test_id
|
395
|
+
xpath = xpath[locator_matchers]
|
396
|
+
end
|
382
397
|
if options.key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
|
383
398
|
with_attr = XPath.attr(:for) == options[:for].to_s
|
384
399
|
labelable_elements = %i[button input keygen meter output progress select textarea]
|
@@ -401,45 +416,50 @@ Capybara.add_selector(:label) do
|
|
401
416
|
end
|
402
417
|
end
|
403
418
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
419
|
+
describe_expression_filters do |**options|
|
420
|
+
" for element with id of \"#{options[:for]}\"" if options.key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
|
421
|
+
end
|
422
|
+
describe_node_filters do |**options|
|
423
|
+
" for element #{options[:for]}" if options[:for]&.is_a?(Capybara::Node::Element)
|
408
424
|
end
|
409
425
|
end
|
410
426
|
|
411
427
|
Capybara.add_selector(:table) do
|
412
|
-
xpath(:caption) do |locator, caption: nil,
|
428
|
+
xpath(:caption) do |locator, caption: nil, **|
|
413
429
|
xpath = XPath.descendant(:table)
|
414
|
-
|
430
|
+
unless locator.nil?
|
431
|
+
locator_matchers = (XPath.attr(:id) == locator.to_s) | XPath.descendant(:caption).is(locator.to_s)
|
432
|
+
locator_matchers |= XPath.attr(test_id) == locator if test_id
|
433
|
+
xpath = xpath[locator_matchers]
|
434
|
+
end
|
415
435
|
xpath = xpath[XPath.descendant(:caption) == caption] if caption
|
416
436
|
xpath
|
417
437
|
end
|
418
438
|
|
419
|
-
|
420
|
-
|
421
|
-
desc << " with caption #{caption}" if caption
|
422
|
-
desc
|
439
|
+
describe_expression_filters do |caption: nil, **|
|
440
|
+
" with caption \"#{caption}\"" if caption
|
423
441
|
end
|
424
442
|
end
|
425
443
|
|
426
444
|
Capybara.add_selector(:frame) do
|
427
445
|
xpath(:name) do |locator, **options|
|
428
446
|
xpath = XPath.descendant(:iframe).union(XPath.descendant(:frame))
|
429
|
-
|
447
|
+
unless locator.nil?
|
448
|
+
locator_matchers = (XPath.attr(:id) == locator.to_s) | (XPath.attr(:name) == locator.to_s)
|
449
|
+
locator_matchers |= XPath.attr(test_id) == locator if test_id
|
450
|
+
xpath = xpath[locator_matchers]
|
451
|
+
end
|
430
452
|
xpath = expression_filters.keys.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
431
453
|
xpath
|
432
454
|
end
|
433
455
|
|
434
|
-
|
435
|
-
|
436
|
-
desc << " with name #{name}" if name
|
437
|
-
desc
|
456
|
+
describe_expression_filters do |name: nil, **|
|
457
|
+
" with name #{name}" if name
|
438
458
|
end
|
439
459
|
end
|
440
460
|
|
441
461
|
Capybara.add_selector(:element) do
|
442
|
-
xpath do |locator,
|
462
|
+
xpath do |locator, **|
|
443
463
|
XPath.descendant((locator || '@').to_sym)
|
444
464
|
end
|
445
465
|
|
@@ -458,10 +478,6 @@ Capybara.add_selector(:element) do
|
|
458
478
|
val.is_a?(Regexp) ? node[name] =~ val : true
|
459
479
|
end
|
460
480
|
|
461
|
-
|
462
|
-
desc = +""
|
463
|
-
desc << describe_all_expression_filters(options)
|
464
|
-
desc
|
465
|
-
end
|
481
|
+
describe_expression_filters
|
466
482
|
end
|
467
483
|
# rubocop:enable Metrics/BlockLength
|
@@ -5,7 +5,7 @@ module Capybara
|
|
5
5
|
class CSS
|
6
6
|
def self.escape(str)
|
7
7
|
value = str.dup
|
8
|
-
out = +
|
8
|
+
out = +''
|
9
9
|
out << value.slice!(0...1) if value =~ /^[-_]/
|
10
10
|
out << (value[0] =~ NMSTART ? value.slice!(0...1) : escape_char(value.slice!(0...1)))
|
11
11
|
out << value.gsub(/[^a-zA-Z0-9_-]/) { |c| escape_char c }
|
@@ -13,7 +13,7 @@ module Capybara
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.escape_char(c)
|
16
|
-
c =~ %r{[ -/:-~]} ? "\\#{c}" : format(
|
16
|
+
c =~ %r{[ -/:-~]} ? "\\#{c}" : format('\\%06x', c.ord)
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.split(css)
|
@@ -31,7 +31,7 @@ module Capybara
|
|
31
31
|
def split(css)
|
32
32
|
selectors = []
|
33
33
|
StringIO.open(css) do |str|
|
34
|
-
selector =
|
34
|
+
selector = ''
|
35
35
|
while (c = str.getc)
|
36
36
|
case c
|
37
37
|
when '['
|
@@ -44,7 +44,7 @@ module Capybara
|
|
44
44
|
selector += c + str.getc
|
45
45
|
when ','
|
46
46
|
selectors << selector.strip
|
47
|
-
selector =
|
47
|
+
selector = ''
|
48
48
|
else
|
49
49
|
selector += c
|
50
50
|
end
|
@@ -5,13 +5,13 @@ require 'capybara/selector/filter'
|
|
5
5
|
module Capybara
|
6
6
|
class Selector
|
7
7
|
class FilterSet
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :node_filters, :expression_filters
|
9
9
|
|
10
10
|
def initialize(name, &block)
|
11
11
|
@name = name
|
12
|
-
@descriptions = []
|
13
|
-
@expression_filters = {}
|
14
12
|
@node_filters = {}
|
13
|
+
@expression_filters = {}
|
14
|
+
@descriptions = Hash.new { |h, k| h[k] = [] }
|
15
15
|
instance_eval(&block)
|
16
16
|
end
|
17
17
|
|
@@ -24,13 +24,43 @@ module Capybara
|
|
24
24
|
add_filter(name, Filters::ExpressionFilter, *types_and_options, &block)
|
25
25
|
end
|
26
26
|
|
27
|
-
def describe(&block)
|
28
|
-
|
27
|
+
def describe(what = nil, &block)
|
28
|
+
case what
|
29
|
+
when nil
|
30
|
+
undeclared_descriptions.push block
|
31
|
+
when :node_filters
|
32
|
+
node_filter_descriptions.push block
|
33
|
+
when :expression_filters
|
34
|
+
expression_filter_descriptions.push block
|
35
|
+
else
|
36
|
+
raise ArgumentError, 'Unknown description type'
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
|
-
def description(**options)
|
40
|
+
def description(node_filters: true, expression_filters: true, **options)
|
32
41
|
opts = options_with_defaults(options)
|
33
|
-
|
42
|
+
d = +''
|
43
|
+
d += undeclared_descriptions.map { |desc| desc.call(opts).to_s }.join
|
44
|
+
d += expression_filter_descriptions.map { |desc| desc.call(opts).to_s }.join if expression_filters
|
45
|
+
d += node_filter_descriptions.map { |desc| desc.call(opts).to_s }.join if node_filters
|
46
|
+
d
|
47
|
+
end
|
48
|
+
|
49
|
+
def descriptions
|
50
|
+
warn 'DEPRECATED: FilterSet#descriptions is deprecated without replacement'
|
51
|
+
[undeclared_descriptions, node_filter_descriptions, expression_filter_descriptions].flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
def import(name, filters = nil)
|
55
|
+
f_set = self.class.all[name]
|
56
|
+
filter_selector = filters.nil? ? ->(*) { true } : ->(n, _) { filters.include? n }
|
57
|
+
|
58
|
+
expression_filters.merge!(f_set.expression_filters.select(&filter_selector))
|
59
|
+
node_filters.merge!(f_set.node_filters.select(&filter_selector))
|
60
|
+
|
61
|
+
f_set.undeclared_descriptions.each { |desc| describe(&desc) }
|
62
|
+
f_set.expression_filter_descriptions.each { |desc| describe(:expression_filters, &desc) }
|
63
|
+
f_set.node_filter_descriptions.each { |desc| describe(:node_filters, &desc) }
|
34
64
|
end
|
35
65
|
|
36
66
|
class << self
|
@@ -47,6 +77,20 @@ module Capybara
|
|
47
77
|
end
|
48
78
|
end
|
49
79
|
|
80
|
+
protected
|
81
|
+
|
82
|
+
def undeclared_descriptions
|
83
|
+
@descriptions[:undeclared]
|
84
|
+
end
|
85
|
+
|
86
|
+
def node_filter_descriptions
|
87
|
+
@descriptions[:node_filters]
|
88
|
+
end
|
89
|
+
|
90
|
+
def expression_filter_descriptions
|
91
|
+
@descriptions[:expression_filters]
|
92
|
+
end
|
93
|
+
|
50
94
|
private
|
51
95
|
|
52
96
|
def options_with_defaults(options)
|
@@ -61,7 +105,7 @@ module Capybara
|
|
61
105
|
|
62
106
|
def add_filter(name, filter_class, *types, matcher: nil, **options, &block)
|
63
107
|
types.each { |k| options[k] = true }
|
64
|
-
raise
|
108
|
+
raise 'ArgumentError', ':default option is not supported for filters with a :matcher option' if matcher && options[:default]
|
65
109
|
if filter_class <= Filters::ExpressionFilter
|
66
110
|
@expression_filters[name] = filter_class.new(name, matcher, block, options)
|
67
111
|
else
|