capybara 3.29.0 → 3.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +91 -1
- data/README.md +10 -3
- data/lib/capybara.rb +17 -7
- data/lib/capybara/config.rb +7 -3
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +3 -1
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +153 -97
- data/lib/capybara/node/actions.rb +35 -35
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +23 -16
- data/lib/capybara/node/finders.rb +17 -11
- data/lib/capybara/node/matchers.rb +64 -51
- data/lib/capybara/node/simple.rb +4 -2
- data/lib/capybara/queries/ancestor_query.rb +1 -1
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/selector_query.rb +25 -5
- data/lib/capybara/queries/sibling_query.rb +1 -1
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +6 -0
- data/lib/capybara/rack_test/browser.rb +7 -2
- data/lib/capybara/rack_test/driver.rb +1 -1
- data/lib/capybara/rack_test/form.rb +1 -1
- data/lib/capybara/rack_test/node.rb +34 -9
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/servers.rb +1 -1
- data/lib/capybara/result.rb +29 -5
- data/lib/capybara/rspec/matcher_proxies.rb +4 -4
- data/lib/capybara/rspec/matchers.rb +27 -27
- data/lib/capybara/rspec/matchers/base.rb +12 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
- data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
- data/lib/capybara/rspec/matchers/have_text.rb +3 -3
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +2 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
- data/lib/capybara/selector.rb +34 -17
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/definition.rb +7 -6
- data/lib/capybara/selector/definition/button.rb +8 -2
- data/lib/capybara/selector/definition/checkbox.rb +2 -2
- data/lib/capybara/selector/definition/css.rb +3 -1
- data/lib/capybara/selector/definition/datalist_input.rb +1 -1
- data/lib/capybara/selector/definition/datalist_option.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +1 -1
- data/lib/capybara/selector/definition/field.rb +1 -1
- data/lib/capybara/selector/definition/file_field.rb +1 -1
- data/lib/capybara/selector/definition/fillable_field.rb +2 -2
- data/lib/capybara/selector/definition/label.rb +4 -2
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/radio_button.rb +2 -2
- data/lib/capybara/selector/definition/select.rb +32 -13
- data/lib/capybara/selector/definition/table.rb +6 -3
- data/lib/capybara/selector/filter_set.rb +11 -9
- data/lib/capybara/selector/filters/base.rb +6 -1
- data/lib/capybara/selector/filters/locator_filter.rb +1 -1
- data/lib/capybara/selector/selector.rb +8 -2
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/driver.rb +22 -11
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +8 -10
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +7 -9
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
- data/lib/capybara/selenium/extensions/html5_drag.rb +30 -13
- data/lib/capybara/selenium/node.rb +97 -18
- data/lib/capybara/selenium/nodes/chrome_node.rb +11 -14
- data/lib/capybara/selenium/nodes/edge_node.rb +4 -2
- data/lib/capybara/selenium/nodes/firefox_node.rb +4 -4
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/logs.rb +3 -5
- data/lib/capybara/server.rb +15 -3
- data/lib/capybara/server/checker.rb +1 -1
- data/lib/capybara/server/middleware.rb +20 -10
- data/lib/capybara/session.rb +43 -26
- data/lib/capybara/session/config.rb +9 -3
- data/lib/capybara/session/matchers.rb +6 -6
- data/lib/capybara/spec/public/test.js +69 -6
- data/lib/capybara/spec/session/all_spec.rb +60 -5
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/click_button_spec.rb +16 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +31 -8
- data/lib/capybara/spec/session/has_button_spec.rb +16 -0
- data/lib/capybara/spec/session/has_css_spec.rb +12 -9
- data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +16 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_table_spec.rb +51 -5
- data/lib/capybara/spec/session/has_text_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +160 -29
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
- data/lib/capybara/spec/session/selectors_spec.rb +15 -2
- data/lib/capybara/spec/session/window/window_spec.rb +7 -7
- data/lib/capybara/spec/spec_helper.rb +2 -2
- data/lib/capybara/spec/test_app.rb +14 -18
- data/lib/capybara/spec/views/form.erb +18 -2
- data/lib/capybara/spec/views/with_dragula.erb +3 -1
- data/lib/capybara/spec/views/with_html.erb +2 -2
- data/lib/capybara/spec/views/with_js.erb +1 -0
- data/lib/capybara/version.rb +1 -1
- data/spec/capybara_spec.rb +1 -1
- data/spec/dsl_spec.rb +16 -3
- data/spec/minitest_spec.rb +1 -1
- data/spec/minitest_spec_spec.rb +46 -46
- data/spec/rack_test_spec.rb +13 -1
- data/spec/regexp_dissassembler_spec.rb +40 -36
- data/spec/result_spec.rb +43 -32
- data/spec/rspec/features_spec.rb +1 -0
- data/spec/rspec/shared_spec_matchers.rb +68 -56
- data/spec/rspec_spec.rb +4 -4
- data/spec/selector_spec.rb +1 -1
- data/spec/selenium_spec_chrome.rb +9 -6
- data/spec/selenium_spec_chrome_remote.rb +2 -0
- data/spec/selenium_spec_firefox.rb +7 -2
- data/spec/server_spec.rb +65 -31
- data/spec/session_spec.rb +1 -1
- data/spec/shared_selenium_node.rb +21 -3
- data/spec/shared_selenium_session.rb +33 -14
- data/spec/spec_helper.rb +1 -1
- metadata +6 -4
data/lib/capybara/node/simple.rb
CHANGED
@@ -108,7 +108,9 @@ module Capybara
|
|
108
108
|
!find_xpath(VISIBILITY_XPATH)
|
109
109
|
else
|
110
110
|
# No need for an xpath if only checking the current element
|
111
|
-
!(native.key?('hidden') ||
|
111
|
+
!(native.key?('hidden') ||
|
112
|
+
/display:\s?none/.match?(native[:style] || '') ||
|
113
|
+
%w[script head].include?(tag_name))
|
112
114
|
end
|
113
115
|
end
|
114
116
|
|
@@ -150,7 +152,7 @@ module Capybara
|
|
150
152
|
yield # simple nodes don't need to wait
|
151
153
|
end
|
152
154
|
|
153
|
-
def allow_reload!
|
155
|
+
def allow_reload!(*)
|
154
156
|
# no op
|
155
157
|
end
|
156
158
|
|
@@ -12,7 +12,7 @@ module Capybara
|
|
12
12
|
ancestors = node.find_xpath(XPath.ancestor.to_s)
|
13
13
|
.map(&method(:to_element))
|
14
14
|
.select { |el| match_results.include?(el) }
|
15
|
-
Capybara::Result.new(ancestors, self)
|
15
|
+
Capybara::Result.new(ordered_results(ancestors), self)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -79,7 +79,8 @@ module Capybara
|
|
79
79
|
if count
|
80
80
|
message << " #{occurrences count}"
|
81
81
|
elsif between
|
82
|
-
message << " between #{between.
|
82
|
+
message << " between #{between.begin ? between.first : 1} and" \
|
83
|
+
" #{between.end ? between.last : 'infinite'} times"
|
83
84
|
elsif maximum
|
84
85
|
message << " at most #{occurrences maximum}"
|
85
86
|
elsif minimum
|
@@ -6,6 +6,7 @@ module Capybara
|
|
6
6
|
module Queries
|
7
7
|
class SelectorQuery < Queries::BaseQuery
|
8
8
|
attr_reader :expression, :selector, :locator, :options
|
9
|
+
|
9
10
|
SPATIAL_KEYS = %i[above below left_of right_of near].freeze
|
10
11
|
VALID_KEYS = SPATIAL_KEYS + COUNT_KEYS +
|
11
12
|
%i[text id class style visible obscured exact exact_text normalize_ws match wait filter_set]
|
@@ -14,13 +15,16 @@ module Capybara
|
|
14
15
|
def initialize(*args,
|
15
16
|
session_options:,
|
16
17
|
enable_aria_label: session_options.enable_aria_label,
|
18
|
+
enable_aria_role: session_options.enable_aria_role,
|
17
19
|
test_id: session_options.test_id,
|
18
20
|
selector_format: nil,
|
21
|
+
order: nil,
|
19
22
|
**options,
|
20
23
|
&filter_block)
|
21
24
|
@resolved_node = nil
|
22
25
|
@resolved_count = 0
|
23
26
|
@options = options.dup
|
27
|
+
@order = order
|
24
28
|
@filter_cache = Hash.new { |hsh, key| hsh[key] = {} }
|
25
29
|
|
26
30
|
super(@options)
|
@@ -28,7 +32,11 @@ module Capybara
|
|
28
32
|
|
29
33
|
@selector = Selector.new(
|
30
34
|
find_selector(args[0].is_a?(Symbol) ? args.shift : args[0]),
|
31
|
-
config: {
|
35
|
+
config: {
|
36
|
+
enable_aria_label: enable_aria_label,
|
37
|
+
enable_aria_role: enable_aria_role,
|
38
|
+
test_id: test_id
|
39
|
+
},
|
32
40
|
format: selector_format
|
33
41
|
)
|
34
42
|
|
@@ -37,7 +45,7 @@ module Capybara
|
|
37
45
|
|
38
46
|
raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
|
39
47
|
|
40
|
-
@expression = selector.call(@locator,
|
48
|
+
@expression = selector.call(@locator, **@options)
|
41
49
|
|
42
50
|
warn_exact_usage
|
43
51
|
|
@@ -77,7 +85,9 @@ module Capybara
|
|
77
85
|
end
|
78
86
|
|
79
87
|
%i[above below left_of right_of near].each do |spatial_filter|
|
80
|
-
|
88
|
+
if options[spatial_filter] && show_for[:spatial]
|
89
|
+
desc << " #{spatial_filter} #{options[spatial_filter] rescue '<ERROR>'}" # rubocop:disable Style/RescueModifier
|
90
|
+
end
|
81
91
|
end
|
82
92
|
|
83
93
|
desc << selector.description(node_filters: show_for[:node], **options)
|
@@ -148,7 +158,7 @@ module Capybara
|
|
148
158
|
|
149
159
|
node.synchronize do
|
150
160
|
children = find_nodes_by_selector_format(node, exact).map(&method(:to_element))
|
151
|
-
Capybara::Result.new(children, self)
|
161
|
+
Capybara::Result.new(ordered_results(children), self)
|
152
162
|
end
|
153
163
|
end
|
154
164
|
|
@@ -311,6 +321,15 @@ module Capybara
|
|
311
321
|
filters
|
312
322
|
end
|
313
323
|
|
324
|
+
def ordered_results(results)
|
325
|
+
case @order
|
326
|
+
when :reverse
|
327
|
+
results.reverse
|
328
|
+
else
|
329
|
+
results
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
314
333
|
def custom_keys
|
315
334
|
@custom_keys ||= node_filters.keys + expression_filters.keys
|
316
335
|
end
|
@@ -338,7 +357,7 @@ module Capybara
|
|
338
357
|
conditions[:id] = options[:id] if use_default_id_filter?
|
339
358
|
conditions[:class] = options[:class] if use_default_class_filter?
|
340
359
|
conditions[:style] = options[:style] if use_default_style_filter? && !options[:style].is_a?(Hash)
|
341
|
-
builder(expr).add_attribute_conditions(conditions)
|
360
|
+
builder(expr).add_attribute_conditions(**conditions)
|
342
361
|
end
|
343
362
|
|
344
363
|
def use_default_id_filter?
|
@@ -562,6 +581,7 @@ module Capybara
|
|
562
581
|
|
563
582
|
class Rectangle
|
564
583
|
attr_reader :top, :bottom, :left, :right
|
584
|
+
|
565
585
|
def initialize(position)
|
566
586
|
# rubocop:disable Style/RescueModifier
|
567
587
|
@top = position['top'] rescue position['y']
|
@@ -11,7 +11,7 @@ module Capybara
|
|
11
11
|
siblings = node.find_xpath((XPath.preceding_sibling + XPath.following_sibling).to_s)
|
12
12
|
.map(&method(:to_element))
|
13
13
|
.select { |el| match_results.include?(el) }
|
14
|
-
Capybara::Result.new(siblings, self)
|
14
|
+
Capybara::Result.new(ordered_results(siblings), self)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -6,6 +6,8 @@ module Capybara
|
|
6
6
|
class TextQuery < BaseQuery
|
7
7
|
def initialize(type = nil, expected_text, session_options:, **options) # rubocop:disable Style/OptionalArguments
|
8
8
|
@type = type.nil? ? default_type : type
|
9
|
+
raise ArgumentError, '${@type} is not a valid type for a text query' unless valid_types.include?(@type)
|
10
|
+
|
9
11
|
@options = options
|
10
12
|
super(@options)
|
11
13
|
self.session_options = session_options
|
@@ -89,6 +91,10 @@ module Capybara
|
|
89
91
|
COUNT_KEYS + %i[wait exact normalize_ws]
|
90
92
|
end
|
91
93
|
|
94
|
+
def valid_types
|
95
|
+
%i[all visible]
|
96
|
+
end
|
97
|
+
|
92
98
|
def check_visible_text?
|
93
99
|
@type == :visible
|
94
100
|
end
|
@@ -30,7 +30,9 @@ class Capybara::RackTest::Browser
|
|
30
30
|
|
31
31
|
def submit(method, path, attributes)
|
32
32
|
path = request_path if path.nil? || path.empty?
|
33
|
-
|
33
|
+
uri = build_uri(path)
|
34
|
+
uri.query = '' if method&.to_s&.downcase == 'get'
|
35
|
+
process_and_follow_redirects(method, uri.to_s, attributes, 'HTTP_REFERER' => current_url)
|
34
36
|
end
|
35
37
|
|
36
38
|
def follow(method, path, **attributes)
|
@@ -53,7 +55,10 @@ class Capybara::RackTest::Browser
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
end
|
56
|
-
|
58
|
+
|
59
|
+
if last_response.redirect? # rubocop:disable Style/GuardClause
|
60
|
+
raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects."
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
64
|
def process(method, path, attributes = {}, env = {})
|
@@ -45,6 +45,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
45
45
|
|
46
46
|
if radio? then set_radio(value)
|
47
47
|
elsif checkbox? then set_checkbox(value)
|
48
|
+
elsif range? then set_range(value)
|
48
49
|
elsif input_field? then set_input(value)
|
49
50
|
elsif textarea? then native['_capybara_raw_value'] = value.to_s
|
50
51
|
end
|
@@ -76,8 +77,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
76
77
|
set(!checked?)
|
77
78
|
elsif tag_name == 'label'
|
78
79
|
click_label
|
79
|
-
elsif
|
80
|
-
toggle_details
|
80
|
+
elsif (details = native.xpath('.//ancestor-or-self::details').last)
|
81
|
+
toggle_details(details)
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
@@ -123,9 +124,18 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
123
124
|
alias_method "unchecked_#{meth_name}", meth_name
|
124
125
|
private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
|
125
126
|
|
126
|
-
|
127
|
-
|
128
|
-
|
127
|
+
if RUBY_VERSION >= '2.7'
|
128
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
129
|
+
def #{meth_name}(...)
|
130
|
+
stale_check
|
131
|
+
method(:"unchecked_#{meth_name}").call(...)
|
132
|
+
end
|
133
|
+
METHOD
|
134
|
+
else
|
135
|
+
define_method meth_name do |*args|
|
136
|
+
stale_check
|
137
|
+
send("unchecked_#{meth_name}", *args)
|
138
|
+
end
|
129
139
|
end
|
130
140
|
end
|
131
141
|
|
@@ -199,6 +209,14 @@ private
|
|
199
209
|
end
|
200
210
|
end
|
201
211
|
|
212
|
+
def set_range(value) # rubocop:disable Naming/AccessorMethodName
|
213
|
+
min, max, step = (native['min'] || 0).to_f, (native['max'] || 100).to_f, (native['step'] || 1).to_f
|
214
|
+
value = value.to_f
|
215
|
+
value = value.clamp(min, max)
|
216
|
+
value = ((value - min) / step).round * step + min
|
217
|
+
native['value'] = value.clamp(min, max)
|
218
|
+
end
|
219
|
+
|
202
220
|
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
203
221
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
204
222
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
@@ -238,11 +256,14 @@ private
|
|
238
256
|
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
239
257
|
end
|
240
258
|
|
241
|
-
def toggle_details
|
242
|
-
|
243
|
-
|
259
|
+
def toggle_details(details = nil)
|
260
|
+
details ||= native.xpath('.//ancestor-or-self::details').last
|
261
|
+
return unless details
|
262
|
+
|
263
|
+
if details.has_attribute?('open')
|
264
|
+
details.remove_attribute('open')
|
244
265
|
else
|
245
|
-
|
266
|
+
details.set_attribute('open', 'open')
|
246
267
|
end
|
247
268
|
end
|
248
269
|
|
@@ -284,6 +305,10 @@ protected
|
|
284
305
|
tag_name == 'textarea'
|
285
306
|
end
|
286
307
|
|
308
|
+
def range?
|
309
|
+
input_field? && type == 'range'
|
310
|
+
end
|
311
|
+
|
287
312
|
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
288
313
|
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
289
314
|
x.parent(:fieldset)[
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
# @api private
|
5
|
+
class RegistrationContainer
|
6
|
+
def names
|
7
|
+
@registered.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](name)
|
11
|
+
@registered[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(name, value)
|
15
|
+
warn 'DEPRECATED: Directly setting drivers/servers is deprecated, please use Capybara.register_driver/register_server instead'
|
16
|
+
@registered[name] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_name, *args, **options, &block)
|
20
|
+
if @registered.respond_to?(method_name)
|
21
|
+
warn "DEPRECATED: Calling '#{method_name}' on the drivers/servers container is deprecated without replacement"
|
22
|
+
# RUBY 2.6 will send an empty hash rather than nothing with **options so fix that
|
23
|
+
return @registered.public_send(method_name, *args, &block) if options.empty?
|
24
|
+
|
25
|
+
return @registered.public_send(method_name, *args, **options, &block)
|
26
|
+
end
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def respond_to_missing?(method_name, include_private = false)
|
31
|
+
@registered.respond_to?(method_name) || super
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
@registered = {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def register(name, block)
|
41
|
+
@registered[name] = block
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -7,7 +7,7 @@ end
|
|
7
7
|
Capybara.register_server :webrick do |app, port, host, **options|
|
8
8
|
require 'rack/handler/webrick'
|
9
9
|
options = { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options)
|
10
|
-
Rack::Handler::WEBrick.run(app, options)
|
10
|
+
Rack::Handler::WEBrick.run(app, **options)
|
11
11
|
end
|
12
12
|
|
13
13
|
Capybara.register_server :puma do |app, port, host, **options|
|
data/lib/capybara/result.rb
CHANGED
@@ -31,6 +31,7 @@ module Capybara
|
|
31
31
|
@filter_errors = []
|
32
32
|
@results_enum = lazy_select_elements { |node| query.matches_filters?(node, @filter_errors) }
|
33
33
|
@query = query
|
34
|
+
@allow_reload = false
|
34
35
|
end
|
35
36
|
|
36
37
|
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
|
@@ -43,7 +44,7 @@ module Capybara
|
|
43
44
|
@result_cache.each(&block)
|
44
45
|
loop do
|
45
46
|
next_result = @results_enum.next
|
46
|
-
|
47
|
+
add_to_cache(next_result)
|
47
48
|
yield next_result
|
48
49
|
end
|
49
50
|
self
|
@@ -59,7 +60,12 @@ module Capybara
|
|
59
60
|
nil
|
60
61
|
end
|
61
62
|
when Range
|
62
|
-
|
63
|
+
# idx.max is broken with beginless ranges
|
64
|
+
# idx.end && idx.max # endless range will have end == nil
|
65
|
+
max = idx.end
|
66
|
+
max = nil if max&.negative?
|
67
|
+
max -= 1 if max && idx.exclude_end?
|
68
|
+
max
|
63
69
|
end
|
64
70
|
|
65
71
|
if max_idx.nil?
|
@@ -94,7 +100,9 @@ module Capybara
|
|
94
100
|
end
|
95
101
|
|
96
102
|
if between
|
97
|
-
min, max = between.
|
103
|
+
min, max = (between.begin && between.min) || 1, between.end
|
104
|
+
max -= 1 if max && between.exclude_end?
|
105
|
+
|
98
106
|
size = load_up_to(max ? max + 1 : min)
|
99
107
|
return size <=> min unless between.include?(size)
|
100
108
|
end
|
@@ -130,13 +138,26 @@ module Capybara
|
|
130
138
|
@elements.length
|
131
139
|
end
|
132
140
|
|
141
|
+
##
|
142
|
+
# @api private
|
143
|
+
#
|
144
|
+
def allow_reload!
|
145
|
+
@allow_reload = true
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
133
149
|
private
|
134
150
|
|
151
|
+
def add_to_cache(elem)
|
152
|
+
elem.allow_reload!(@result_cache.size) if @allow_reload
|
153
|
+
@result_cache << elem
|
154
|
+
end
|
155
|
+
|
135
156
|
def load_up_to(num)
|
136
157
|
loop do
|
137
158
|
break if @result_cache.size >= num
|
138
159
|
|
139
|
-
@
|
160
|
+
add_to_cache(@results_enum.next)
|
140
161
|
end
|
141
162
|
@result_cache.size
|
142
163
|
end
|
@@ -150,10 +171,13 @@ module Capybara
|
|
150
171
|
@rest ||= @elements - full_results
|
151
172
|
end
|
152
173
|
|
153
|
-
if
|
174
|
+
if RUBY_PLATFORM == 'java'
|
154
175
|
# JRuby < 9.2.8.0 has an issue with lazy enumerators which
|
155
176
|
# causes a concurrency issue with network requests here
|
156
177
|
# https://github.com/jruby/jruby/issues/4212
|
178
|
+
# while JRuby >= 9.2.8.0 leaks threads when using lazy enumerators
|
179
|
+
# https://github.com/teamcapybara/capybara/issues/2349
|
180
|
+
# so disable the use and JRuby users will need to pay a performance penalty
|
157
181
|
def lazy_select_elements(&block)
|
158
182
|
@elements.select(&block).to_enum # non-lazy evaluation
|
159
183
|
end
|
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
module Capybara
|
4
4
|
module RSpecMatcherProxies
|
5
|
-
def all(*args, &block)
|
5
|
+
def all(*args, **kwargs, &block)
|
6
6
|
if defined?(::RSpec::Matchers::BuiltIn::All) && args.first.respond_to?(:matches?)
|
7
7
|
::RSpec::Matchers::BuiltIn::All.new(*args)
|
8
8
|
else
|
9
|
-
find_all(*args, &block)
|
9
|
+
find_all(*args, **kwargs, &block)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def within(*args, &block)
|
13
|
+
def within(*args, **kwargs, &block)
|
14
14
|
if block_given?
|
15
|
-
within_element(*args, &block)
|
15
|
+
within_element(*args, **kwargs, &block)
|
16
16
|
else
|
17
17
|
be_within(*args)
|
18
18
|
end
|