capybara 2.15.0 → 3.0.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 +137 -2
- data/README.md +36 -25
- data/lib/capybara/config.rb +11 -57
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +19 -16
- data/lib/capybara/driver/node.rb +5 -4
- data/lib/capybara/dsl.rb +1 -0
- data/lib/capybara/helpers.rb +19 -29
- data/lib/capybara/minitest/spec.rb +16 -13
- data/lib/capybara/minitest.rb +140 -137
- data/lib/capybara/node/actions.rb +68 -89
- data/lib/capybara/node/base.rb +11 -18
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +8 -8
- data/lib/capybara/node/element.rb +32 -42
- data/lib/capybara/node/finders.rb +64 -71
- data/lib/capybara/node/matchers.rb +50 -71
- data/lib/capybara/node/simple.rb +11 -17
- data/lib/capybara/queries/ancestor_query.rb +12 -8
- data/lib/capybara/queries/base_query.rb +22 -18
- data/lib/capybara/queries/current_path_query.rb +12 -25
- data/lib/capybara/queries/match_query.rb +3 -7
- data/lib/capybara/queries/selector_query.rb +100 -96
- data/lib/capybara/queries/sibling_query.rb +5 -5
- data/lib/capybara/queries/text_query.rb +35 -35
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +15 -18
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +6 -10
- data/lib/capybara/rack_test/form.rb +52 -39
- data/lib/capybara/rack_test/node.rb +93 -63
- data/lib/capybara/rails.rb +2 -6
- data/lib/capybara/result.rb +22 -22
- data/lib/capybara/rspec/compound.rb +5 -10
- data/lib/capybara/rspec/features.rb +17 -48
- data/lib/capybara/rspec/matcher_proxies.rb +31 -15
- data/lib/capybara/rspec/matchers.rb +116 -58
- data/lib/capybara/rspec.rb +5 -10
- data/lib/capybara/selector/css.rb +6 -11
- data/lib/capybara/selector/filter.rb +1 -17
- data/lib/capybara/selector/filter_set.rb +18 -15
- data/lib/capybara/selector/filters/base.rb +7 -6
- data/lib/capybara/selector/filters/expression_filter.rb +6 -23
- data/lib/capybara/selector/filters/node_filter.rb +2 -12
- data/lib/capybara/selector/selector.rb +28 -34
- data/lib/capybara/selector.rb +129 -117
- data/lib/capybara/selenium/driver.rb +172 -163
- data/lib/capybara/selenium/node.rb +218 -104
- data/lib/capybara/server.rb +3 -2
- data/lib/capybara/session/config.rb +47 -59
- data/lib/capybara/session/matchers.rb +23 -14
- data/lib/capybara/session.rb +175 -229
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/test.js +38 -6
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +30 -1
- data/lib/capybara/spec/session/all_spec.rb +31 -18
- data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
- data/lib/capybara/spec/session/assert_current_path.rb +12 -11
- data/lib/capybara/spec/session/assert_selector.rb +1 -0
- data/lib/capybara/spec/session/assert_text.rb +31 -23
- data/lib/capybara/spec/session/assert_title.rb +13 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +57 -29
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +7 -6
- data/lib/capybara/spec/session/choose_spec.rb +5 -4
- data/lib/capybara/spec/session/click_button_spec.rb +24 -32
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
- data/lib/capybara/spec/session/click_link_spec.rb +8 -7
- data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
- data/lib/capybara/spec/session/current_url_spec.rb +19 -8
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +5 -4
- data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
- data/lib/capybara/spec/session/find_button_spec.rb +4 -3
- data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
- data/lib/capybara/spec/session/find_field_spec.rb +9 -15
- data/lib/capybara/spec/session/find_link_spec.rb +6 -5
- data/lib/capybara/spec/session/find_spec.rb +37 -31
- data/lib/capybara/spec/session/first_spec.rb +60 -33
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
- data/lib/capybara/spec/session/go_back_spec.rb +1 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_button_spec.rb +2 -1
- data/lib/capybara/spec/session/has_css_spec.rb +3 -2
- data/lib/capybara/spec/session/has_current_path_spec.rb +49 -22
- data/lib/capybara/spec/session/has_field_spec.rb +4 -3
- data/lib/capybara/spec/session/has_link_spec.rb +5 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -31
- data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
- data/lib/capybara/spec/session/has_table_spec.rb +2 -1
- data/lib/capybara/spec/session/has_text_spec.rb +9 -13
- data/lib/capybara/spec/session/has_title_spec.rb +1 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +1 -0
- data/lib/capybara/spec/session/node_spec.rb +107 -58
- data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
- data/lib/capybara/spec/session/refresh_spec.rb +6 -2
- data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
- data/lib/capybara/spec/session/response_code.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
- data/lib/capybara/spec/session/save_page_spec.rb +1 -17
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +21 -20
- data/lib/capybara/spec/session/selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/sibling_spec.rb +1 -1
- data/lib/capybara/spec/session/text_spec.rb +17 -3
- data/lib/capybara/spec/session/title_spec.rb +11 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
- data/lib/capybara/spec/session/unselect_spec.rb +7 -6
- data/lib/capybara/spec/session/visit_spec.rb +64 -3
- data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_spec.rb +12 -12
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
- data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +36 -18
- data/lib/capybara/spec/test_app.rb +17 -9
- data/lib/capybara/spec/views/form.erb +7 -0
- 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 +27 -1
- data/lib/capybara/spec/views/with_js.erb +11 -0
- data/lib/capybara/spec/views/within_frames.erb +4 -1
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +6 -10
- data/lib/capybara.rb +29 -26
- data/spec/basic_node_spec.rb +1 -0
- data/spec/capybara_spec.rb +16 -69
- data/spec/dsl_spec.rb +5 -13
- data/spec/filter_set_spec.rb +5 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
- data/spec/minitest_spec.rb +13 -4
- data/spec/minitest_spec_spec.rb +12 -3
- data/spec/per_session_config_spec.rb +9 -8
- data/spec/rack_test_spec.rb +21 -20
- data/spec/result_spec.rb +17 -16
- data/spec/rspec/features_spec.rb +17 -14
- data/spec/rspec/scenarios_spec.rb +5 -7
- data/spec/rspec/shared_spec_matchers.rb +96 -99
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_matchers_spec.rb +18 -2
- data/spec/rspec_spec.rb +11 -15
- data/spec/selector_spec.rb +5 -6
- data/spec/selenium_spec_chrome.rb +20 -11
- data/spec/selenium_spec_edge.rb +27 -0
- data/spec/selenium_spec_ie.rb +31 -0
- data/spec/selenium_spec_marionette.rb +38 -12
- data/spec/server_spec.rb +33 -33
- data/spec/session_spec.rb +2 -1
- data/spec/shared_selenium_session.rb +82 -22
- data/spec/spec_helper.rb +3 -6
- metadata +76 -81
- data/lib/capybara/query.rb +0 -7
- data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
5
|
module Actions
|
5
|
-
|
6
6
|
##
|
7
7
|
#
|
8
|
-
# Finds a button or link
|
9
|
-
#
|
8
|
+
# Finds a button or link and clicks it. See {Capybara::Node::Actions#click_button} and
|
9
|
+
# {Capybara::Node::Actions#click_link} for what locator will match against for each type of element
|
10
10
|
# @!macro waiting_behavior
|
11
11
|
# If the driver is capable of executing JavaScript, +$0+ will wait for a set amount of time
|
12
12
|
# and continuously retry finding the element until either the element is found or the time
|
@@ -16,12 +16,11 @@ module Capybara
|
|
16
16
|
#
|
17
17
|
# @overload click_link_or_button([locator], options)
|
18
18
|
#
|
19
|
-
# @param [String] locator
|
19
|
+
# @param [String] locator See {Capybara::Node::Actions#click_button} and {Capybara::Node::Actions#click_link}
|
20
20
|
#
|
21
21
|
# @return [Capybara::Node::Element] The element clicked
|
22
22
|
#
|
23
|
-
def click_link_or_button(locator=nil, options
|
24
|
-
locator, options = nil, locator if locator.is_a? Hash
|
23
|
+
def click_link_or_button(locator = nil, **options)
|
25
24
|
find(:link_or_button, locator, options).click
|
26
25
|
end
|
27
26
|
alias_method :click_on, :click_link_or_button
|
@@ -38,8 +37,7 @@ module Capybara
|
|
38
37
|
# @param options See {Capybara::Node::Finders#find_link}
|
39
38
|
#
|
40
39
|
# @return [Capybara::Node::Element] The element clicked
|
41
|
-
def click_link(locator=nil, options
|
42
|
-
locator, options = nil, locator if locator.is_a? Hash
|
40
|
+
def click_link(locator = nil, **options)
|
43
41
|
find(:link, locator, options).click
|
44
42
|
end
|
45
43
|
|
@@ -56,8 +54,7 @@ module Capybara
|
|
56
54
|
# @param [String] locator Which button to find
|
57
55
|
# @param options See {Capybara::Node::Finders#find_button}
|
58
56
|
# @return [Capybara::Node::Element] The element clicked
|
59
|
-
def click_button(locator=nil, options
|
60
|
-
locator, options = nil, locator if locator.is_a? Hash
|
57
|
+
def click_button(locator = nil, **options)
|
61
58
|
find(:button, locator, options).click
|
62
59
|
end
|
63
60
|
|
@@ -80,15 +77,11 @@ module Capybara
|
|
80
77
|
# @option options [String] :id Match fields that match the id attribute
|
81
78
|
# @option options [String] :name Match fields that match the name attribute
|
82
79
|
# @option options [String] :placeholder Match fields that match the placeholder attribute
|
83
|
-
# @option options [String, Array<String>] :class Match
|
80
|
+
# @option options [String, Array<String>] :class Match fields that match the class(es) provided
|
84
81
|
#
|
85
82
|
# @return [Capybara::Node::Element] The element filled_in
|
86
|
-
def fill_in(locator,
|
87
|
-
|
88
|
-
raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
|
89
|
-
with = options.delete(:with)
|
90
|
-
fill_options = options.delete(:fill_options)
|
91
|
-
options[:with] = options.delete(:currently_with) if options.has_key?(:currently_with)
|
83
|
+
def fill_in(locator = nil, with:, fill_options: {}, **options)
|
84
|
+
options[:with] = options.delete(:currently_with) if options.key?(:currently_with)
|
92
85
|
find(:fillable_field, locator, options).set(with, fill_options)
|
93
86
|
end
|
94
87
|
|
@@ -108,13 +101,13 @@ module Capybara
|
|
108
101
|
# @option options [String] :option Value of the radio_button to choose
|
109
102
|
# @option options [String] :id Match fields that match the id attribute
|
110
103
|
# @option options [String] :name Match fields that match the name attribute
|
111
|
-
# @option options [String, Array<String>] :class Match
|
104
|
+
# @option options [String, Array<String>] :class Match fields that match the class(es) provided
|
112
105
|
# @macro waiting_behavior
|
113
106
|
# @macro label_click
|
114
107
|
#
|
115
108
|
# @return [Capybara::Node::Element] The element chosen or the label clicked
|
116
|
-
def choose(locator, options
|
117
|
-
_check_with_label(:radio_button, true, locator, options)
|
109
|
+
def choose(locator = nil, **options)
|
110
|
+
_check_with_label(:radio_button, true, locator, **options)
|
118
111
|
end
|
119
112
|
|
120
113
|
##
|
@@ -131,13 +124,13 @@ module Capybara
|
|
131
124
|
# @option options [String] :option Value of the checkbox to select
|
132
125
|
# @option options [String] id Match fields that match the id attribute
|
133
126
|
# @option options [String] name Match fields that match the name attribute
|
134
|
-
# @option options [String, Array<String>] :class Match
|
127
|
+
# @option options [String, Array<String>] :class Match fields that match the class(es) provided
|
135
128
|
# @macro label_click
|
136
129
|
# @macro waiting_behavior
|
137
130
|
#
|
138
131
|
# @return [Capybara::Node::Element] The element checked or the label clicked
|
139
|
-
def check(locator, options
|
140
|
-
_check_with_label(:checkbox, true, locator, options)
|
132
|
+
def check(locator, **options)
|
133
|
+
_check_with_label(:checkbox, true, locator, **options)
|
141
134
|
end
|
142
135
|
|
143
136
|
##
|
@@ -154,13 +147,13 @@ module Capybara
|
|
154
147
|
# @option options [String] :option Value of the checkbox to deselect
|
155
148
|
# @option options [String] id Match fields that match the id attribute
|
156
149
|
# @option options [String] name Match fields that match the name attribute
|
157
|
-
# @option options [String, Array<String>] :class Match
|
150
|
+
# @option options [String, Array<String>] :class Match fields that match the class(es) provided
|
158
151
|
# @macro label_click
|
159
152
|
# @macro waiting_behavior
|
160
153
|
#
|
161
154
|
# @return [Capybara::Node::Element] The element unchecked or the label clicked
|
162
|
-
def uncheck(locator, options
|
163
|
-
_check_with_label(:checkbox, false, locator, options)
|
155
|
+
def uncheck(locator = nil, **options)
|
156
|
+
_check_with_label(:checkbox, false, locator, **options)
|
164
157
|
end
|
165
158
|
|
166
159
|
##
|
@@ -180,13 +173,9 @@ module Capybara
|
|
180
173
|
# @option options [String] :from The id, name or label of the select box
|
181
174
|
#
|
182
175
|
# @return [Capybara::Node::Element] The option element selected
|
183
|
-
def select(value, options
|
184
|
-
|
185
|
-
|
186
|
-
find(:select, from, options).find(:option, value, options).select_option
|
187
|
-
else
|
188
|
-
find(:option, value, options).select_option
|
189
|
-
end
|
176
|
+
def select(value = nil, from: nil, **options)
|
177
|
+
scope = from ? find(:select, from, options) : self
|
178
|
+
scope.find(:option, value, options).select_option
|
190
179
|
end
|
191
180
|
|
192
181
|
##
|
@@ -203,13 +192,9 @@ module Capybara
|
|
203
192
|
# @param [Hash{:from => String}] options The id, name or label of the select box
|
204
193
|
#
|
205
194
|
# @return [Capybara::Node::Element] The option element unselected
|
206
|
-
def unselect(value, options
|
207
|
-
|
208
|
-
|
209
|
-
find(:select, from, options).find(:option, value, options).unselect_option
|
210
|
-
else
|
211
|
-
find(:option, value, options).unselect_option
|
212
|
-
end
|
195
|
+
def unselect(value = nil, from: nil, **options)
|
196
|
+
scope = from ? find(:select, from, options) : self
|
197
|
+
scope.find(:option, value, options).unselect_option
|
213
198
|
end
|
214
199
|
|
215
200
|
##
|
@@ -229,72 +214,48 @@ module Capybara
|
|
229
214
|
# @option options [Boolean] multiple Match field which allows multiple file selection
|
230
215
|
# @option options [String] id Match fields that match the id attribute
|
231
216
|
# @option options [String] name Match fields that match the name attribute
|
232
|
-
# @option options [String, Array<String>] :class Match
|
217
|
+
# @option options [String, Array<String>] :class Match fields that match the class(es) provided
|
233
218
|
# @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
|
234
219
|
#
|
235
220
|
# @return [Capybara::Node::Element] The file field element
|
236
|
-
def attach_file(locator, path, options
|
237
|
-
locator, path, options = nil, locator, path if path.is_a? Hash
|
221
|
+
def attach_file(locator = nil, path, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
|
238
222
|
Array(path).each do |p|
|
239
223
|
raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
|
240
224
|
end
|
241
225
|
# Allow user to update the CSS style of the file input since they are so often hidden on a page
|
242
|
-
if
|
243
|
-
|
244
|
-
ff
|
245
|
-
_update_style(ff, style)
|
246
|
-
if ff.visible?
|
247
|
-
begin
|
248
|
-
ff.set(path)
|
249
|
-
ensure
|
250
|
-
_reset_style(ff)
|
251
|
-
end
|
252
|
-
else
|
253
|
-
raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible"
|
254
|
-
end
|
226
|
+
if make_visible
|
227
|
+
ff = find(:file_field, locator, options.merge(visible: :all))
|
228
|
+
while_visible(ff, make_visible) { |el| el.set(path) }
|
255
229
|
else
|
256
230
|
find(:file_field, locator, options).set(path)
|
257
231
|
end
|
258
232
|
end
|
259
233
|
|
260
234
|
private
|
261
|
-
def _update_style(element, style)
|
262
|
-
script = <<-JS
|
263
|
-
var el = arguments[0];
|
264
|
-
el.capybara_style_cache = el.style.cssText;
|
265
|
-
var css = arguments[1];
|
266
|
-
for (var prop in css){
|
267
|
-
if (css.hasOwnProperty(prop)) {
|
268
|
-
el.style[prop] = css[prop]
|
269
|
-
}
|
270
|
-
}
|
271
|
-
JS
|
272
|
-
begin
|
273
|
-
session.execute_script(script, element, style)
|
274
|
-
rescue Capybara::NotSupportedByDriverError
|
275
|
-
warn "The :make_visible option is not supported by the current driver - ignoring"
|
276
|
-
end
|
277
|
-
end
|
278
235
|
|
279
|
-
def
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
el.style.cssText = el.capybara_style_cache;
|
284
|
-
delete el.capybara_style_cache;
|
285
|
-
}
|
286
|
-
JS
|
236
|
+
def while_visible(element, visible_css)
|
237
|
+
visible_css = { opacity: 1, display: 'block', visibility: 'visible' } if visible_css == true
|
238
|
+
_update_style(element, visible_css)
|
239
|
+
raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible" unless element.visible?
|
287
240
|
begin
|
288
|
-
|
289
|
-
|
241
|
+
yield element
|
242
|
+
ensure
|
243
|
+
_reset_style(element)
|
290
244
|
end
|
291
245
|
end
|
292
246
|
|
247
|
+
def _update_style(element, style)
|
248
|
+
session.execute_script(UPDATE_STYLE_SCRIPT, element, style)
|
249
|
+
rescue Capybara::NotSupportedByDriverError
|
250
|
+
warn "The :make_visible option is not supported by the current driver - ignoring"
|
251
|
+
end
|
293
252
|
|
294
|
-
def
|
295
|
-
|
296
|
-
|
253
|
+
def _reset_style(element)
|
254
|
+
session.execute_script(RESET_STYLE_SCRIPT, element)
|
255
|
+
rescue # swallow extra errors
|
256
|
+
end
|
297
257
|
|
258
|
+
def _check_with_label(selector, checked, locator, allow_label_click: session_options.automatic_label_click, **options)
|
298
259
|
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
299
260
|
begin
|
300
261
|
el = find(selector, locator, options)
|
@@ -303,15 +264,33 @@ module Capybara
|
|
303
264
|
raise unless allow_label_click && catch_error?(e)
|
304
265
|
begin
|
305
266
|
el ||= find(selector, locator, options.merge(visible: :all))
|
306
|
-
|
307
|
-
|
308
|
-
rescue
|
267
|
+
res = find(:label, for: el, visible: true).click unless el.checked? == checked
|
268
|
+
res
|
269
|
+
rescue # swallow extra errors - raise original
|
309
270
|
raise e
|
310
271
|
end
|
311
272
|
end
|
312
273
|
end
|
313
274
|
end
|
314
275
|
|
276
|
+
UPDATE_STYLE_SCRIPT = <<-'JS'.freeze
|
277
|
+
var el = arguments[0];
|
278
|
+
el.capybara_style_cache = el.style.cssText;
|
279
|
+
var css = arguments[1];
|
280
|
+
for (var prop in css){
|
281
|
+
if (css.hasOwnProperty(prop)) {
|
282
|
+
el.style[prop] = css[prop]
|
283
|
+
}
|
284
|
+
}
|
285
|
+
JS
|
286
|
+
|
287
|
+
RESET_STYLE_SCRIPT = <<-'JS'.freeze
|
288
|
+
var el = arguments[0];
|
289
|
+
if (el.hasOwnProperty('capybara_style_cache')) {
|
290
|
+
el.style.cssText = el.capybara_style_cache;
|
291
|
+
delete el.capybara_style_cache;
|
292
|
+
}
|
293
|
+
JS
|
315
294
|
end
|
316
295
|
end
|
317
296
|
end
|
data/lib/capybara/node/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
|
-
|
5
5
|
##
|
6
6
|
#
|
7
7
|
# A {Capybara::Node::Base} represents either an element on a page through the subclass
|
@@ -67,26 +67,23 @@ module Capybara
|
|
67
67
|
# time has passed. On rubies/platforms which don't support access to a monotonic process clock
|
68
68
|
# if the return value of `Time.now` is stubbed out, Capybara will raise `Capybara::FrozenInTime`.
|
69
69
|
#
|
70
|
-
# @param [Integer] seconds
|
71
|
-
# @param
|
72
|
-
# @option options [Array<Exception>] :errors (driver.invalid_element_errors +
|
70
|
+
# @param [Integer] seconds (current sessions default_max_wait_time) Maximum number of seconds to retry this block
|
71
|
+
# @param [Array<Exception>] errors (driver.invalid_element_errors +
|
73
72
|
# [Capybara::ElementNotFound]) exception types that cause the block to be rerun
|
74
73
|
# @return [Object] The result of the given block
|
75
74
|
# @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck
|
76
75
|
#
|
77
|
-
def synchronize(seconds=session_options.default_max_wait_time,
|
78
|
-
start_time = Capybara::Helpers.monotonic_time
|
79
|
-
|
76
|
+
def synchronize(seconds = session_options.default_max_wait_time, errors: nil)
|
80
77
|
if session.synchronized
|
81
78
|
yield
|
82
79
|
else
|
83
80
|
session.synchronized = true
|
81
|
+
start_time = Capybara::Helpers.monotonic_time
|
84
82
|
begin
|
85
83
|
yield
|
86
84
|
rescue => e
|
87
85
|
session.raise_server_error!
|
88
|
-
raise e unless driver.wait?
|
89
|
-
raise e unless catch_error?(e, options[:errors])
|
86
|
+
raise e unless driver.wait? && catch_error?(e, errors)
|
90
87
|
raise e if (Capybara::Helpers.monotonic_time - start_time) >= seconds
|
91
88
|
sleep(0.05)
|
92
89
|
raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Capybara::Helpers.monotonic_time == start_time
|
@@ -108,24 +105,20 @@ module Capybara
|
|
108
105
|
base.find_xpath(xpath)
|
109
106
|
end
|
110
107
|
|
111
|
-
# @deprecated Use query_scope instead
|
112
|
-
def parent
|
113
|
-
warn "DEPRECATED: #parent is deprecated in favor of #query_scope - Note: #parent was not the elements parent in the document so it's most likely not what you wanted anyway"
|
114
|
-
query_scope
|
115
|
-
end
|
116
|
-
|
117
108
|
# @api private
|
118
109
|
def session_options
|
119
110
|
session.config
|
120
111
|
end
|
121
112
|
|
113
|
+
def to_capybara_node
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
122
117
|
protected
|
123
118
|
|
124
119
|
def catch_error?(error, errors = nil)
|
125
120
|
errors ||= (driver.invalid_element_errors + [Capybara::ElementNotFound])
|
126
|
-
errors.any?
|
127
|
-
error.is_a?(type)
|
128
|
-
end
|
121
|
+
errors.any? { |type| error.is_a?(type) }
|
129
122
|
end
|
130
123
|
|
131
124
|
def driver
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
|
-
|
5
5
|
##
|
6
6
|
#
|
7
7
|
# A {Capybara::Document} represents an HTML document. Any operation
|
@@ -20,7 +20,7 @@ module Capybara
|
|
20
20
|
#
|
21
21
|
# @return [String] The text of the document
|
22
22
|
#
|
23
|
-
def text(type=nil)
|
23
|
+
def text(type = nil)
|
24
24
|
find(:xpath, '/html').text(type)
|
25
25
|
end
|
26
26
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
5
|
module DocumentMatchers
|
@@ -15,8 +16,8 @@ module Capybara
|
|
15
16
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
16
17
|
# @return [true]
|
17
18
|
#
|
18
|
-
def assert_title(title, options
|
19
|
-
_verify_title(title,options) { |query| raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self) }
|
19
|
+
def assert_title(title, **options)
|
20
|
+
_verify_title(title, options) { |query| raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self) }
|
20
21
|
end
|
21
22
|
|
22
23
|
##
|
@@ -26,8 +27,8 @@ module Capybara
|
|
26
27
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
27
28
|
# @return [true]
|
28
29
|
#
|
29
|
-
def assert_no_title(title, options
|
30
|
-
_verify_title(title,options) { |query| raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self) }
|
30
|
+
def assert_no_title(title, **options)
|
31
|
+
_verify_title(title, options) { |query| raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self) }
|
31
32
|
end
|
32
33
|
|
33
34
|
##
|
@@ -36,7 +37,7 @@ module Capybara
|
|
36
37
|
# @macro title_query_params
|
37
38
|
# @return [Boolean]
|
38
39
|
#
|
39
|
-
def has_title?(title, options
|
40
|
+
def has_title?(title, **options)
|
40
41
|
assert_title(title, options)
|
41
42
|
rescue Capybara::ExpectationNotMet
|
42
43
|
return false
|
@@ -48,13 +49,13 @@ module Capybara
|
|
48
49
|
# @macro title_query_params
|
49
50
|
# @return [Boolean]
|
50
51
|
#
|
51
|
-
def has_no_title?(title, options
|
52
|
+
def has_no_title?(title, **options)
|
52
53
|
assert_no_title(title, options)
|
53
54
|
rescue Capybara::ExpectationNotMet
|
54
55
|
return false
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
private
|
58
59
|
|
59
60
|
def _verify_title(title, options)
|
60
61
|
query = Capybara::Queries::TitleQuery.new(title, options)
|
@@ -63,7 +64,6 @@ module Capybara
|
|
63
64
|
end
|
64
65
|
return true
|
65
66
|
end
|
66
|
-
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Capybara
|
3
4
|
module Node
|
4
|
-
|
5
5
|
##
|
6
6
|
#
|
7
7
|
# A {Capybara::Node::Element} represents a single element on the page. It is possible
|
@@ -22,7 +22,6 @@ module Capybara
|
|
22
22
|
# @see Capybara::Node
|
23
23
|
#
|
24
24
|
class Element < Base
|
25
|
-
|
26
25
|
def initialize(session, base, query_scope, query)
|
27
26
|
super(session, base)
|
28
27
|
@query_scope = query_scope
|
@@ -54,7 +53,7 @@ module Capybara
|
|
54
53
|
# @param [:all, :visible] type Whether to return only visible or all text
|
55
54
|
# @return [String] The text of the element
|
56
55
|
#
|
57
|
-
def text(type=nil)
|
56
|
+
def text(type = nil)
|
58
57
|
type ||= :all unless session_options.ignore_hidden_elements or session_options.visible_text_only
|
59
58
|
synchronize do
|
60
59
|
if type == :all
|
@@ -94,23 +93,10 @@ module Capybara
|
|
94
93
|
# @param [Hash{}] options Driver specific options for how to set the value
|
95
94
|
#
|
96
95
|
# @return [Capybara::Node::Element] The element
|
97
|
-
def set(value, options
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
unless options.empty? || driver_supports_options
|
103
|
-
warn "Options passed to Capybara::Node#set but the driver doesn't support them"
|
104
|
-
end
|
105
|
-
|
106
|
-
synchronize do
|
107
|
-
if driver_supports_options
|
108
|
-
base.set(value, options)
|
109
|
-
else
|
110
|
-
base.set(value)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
return self
|
96
|
+
def set(value, **options)
|
97
|
+
raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if readonly?
|
98
|
+
synchronize { base.set(value, options) }
|
99
|
+
self
|
114
100
|
end
|
115
101
|
|
116
102
|
##
|
@@ -121,7 +107,7 @@ module Capybara
|
|
121
107
|
def select_option
|
122
108
|
warn "Attempt to select disabled option: #{value || text}" if disabled?
|
123
109
|
synchronize { base.select_option }
|
124
|
-
|
110
|
+
self
|
125
111
|
end
|
126
112
|
|
127
113
|
##
|
@@ -131,37 +117,43 @@ module Capybara
|
|
131
117
|
# @return [Capybara::Node::Element] The element
|
132
118
|
def unselect_option
|
133
119
|
synchronize { base.unselect_option }
|
134
|
-
|
120
|
+
self
|
135
121
|
end
|
136
122
|
|
137
123
|
##
|
138
124
|
#
|
139
125
|
# Click the Element
|
140
126
|
#
|
127
|
+
# @!macro click_modifiers
|
128
|
+
# @overload $0(*key_modifiers=[], offset={x: nil, y: nil})
|
129
|
+
# @param [Array<:alt, :control, :meta, :shift>] *key_modifiers Keys to be held down when clicking
|
130
|
+
# @param [Hash] offset x and y coordinates to offset the click location from the top left corner of the element. If not specified will click the middle of the element.
|
141
131
|
# @return [Capybara::Node::Element] The element
|
142
|
-
def click
|
143
|
-
synchronize { base.click }
|
144
|
-
|
132
|
+
def click(*keys, **offset)
|
133
|
+
synchronize { base.click(keys, offset) }
|
134
|
+
self
|
145
135
|
end
|
146
136
|
|
147
137
|
##
|
148
138
|
#
|
149
139
|
# Right Click the Element
|
150
140
|
#
|
141
|
+
# @macro click_modifiers
|
151
142
|
# @return [Capybara::Node::Element] The element
|
152
|
-
def right_click
|
153
|
-
synchronize { base.right_click }
|
154
|
-
|
143
|
+
def right_click(*keys, **offset)
|
144
|
+
synchronize { base.right_click(keys, offset) }
|
145
|
+
self
|
155
146
|
end
|
156
147
|
|
157
148
|
##
|
158
149
|
#
|
159
150
|
# Double Click the Element
|
160
151
|
#
|
152
|
+
# @macro click_modifiers
|
161
153
|
# @return [Capybara::Node::Element] The element
|
162
|
-
def double_click
|
163
|
-
synchronize { base.double_click }
|
164
|
-
|
154
|
+
def double_click(*keys, **offset)
|
155
|
+
synchronize { base.double_click(keys, offset) }
|
156
|
+
self
|
165
157
|
end
|
166
158
|
|
167
159
|
##
|
@@ -237,7 +229,7 @@ module Capybara
|
|
237
229
|
# @return [Capybara::Node::Element] The element
|
238
230
|
def send_keys(*args)
|
239
231
|
synchronize { base.send_keys(*args) }
|
240
|
-
|
232
|
+
self
|
241
233
|
end
|
242
234
|
|
243
235
|
##
|
@@ -247,7 +239,7 @@ module Capybara
|
|
247
239
|
# @return [Capybara::Node::Element] The element
|
248
240
|
def hover
|
249
241
|
synchronize { base.hover }
|
250
|
-
|
242
|
+
self
|
251
243
|
end
|
252
244
|
|
253
245
|
##
|
@@ -339,7 +331,7 @@ module Capybara
|
|
339
331
|
# @return [Capybara::Node::Element] The element
|
340
332
|
def trigger(event)
|
341
333
|
synchronize { base.trigger(event) }
|
342
|
-
|
334
|
+
self
|
343
335
|
end
|
344
336
|
|
345
337
|
##
|
@@ -355,7 +347,7 @@ module Capybara
|
|
355
347
|
# @return [Capybara::Node::Element] The element
|
356
348
|
def drag_to(node)
|
357
349
|
synchronize { base.drag_to(node.base) }
|
358
|
-
|
350
|
+
self
|
359
351
|
end
|
360
352
|
|
361
353
|
def reload
|
@@ -371,15 +363,13 @@ module Capybara
|
|
371
363
|
end
|
372
364
|
|
373
365
|
def inspect
|
374
|
-
%(#<Capybara::Node::Element tag="#{tag_name}" path="#{path}">)
|
366
|
+
%(#<Capybara::Node::Element tag="#{base.tag_name}" path="#{base.path}">)
|
375
367
|
rescue NotSupportedByDriverError
|
376
|
-
%(#<Capybara::Node::Element tag="#{tag_name}">)
|
368
|
+
%(#<Capybara::Node::Element tag="#{base.tag_name}">)
|
377
369
|
rescue => e
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
raise
|
382
|
-
end
|
370
|
+
raise unless session.driver.invalid_element_errors.any? { |et| e.is_a?(et) }
|
371
|
+
|
372
|
+
%(Obsolete #<Capybara::Node::Element>)
|
383
373
|
end
|
384
374
|
end
|
385
375
|
end
|