capybara 3.30.0 → 3.31.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 +21 -0
- data/README.md +1 -1
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/minitest.rb +18 -4
- data/lib/capybara/node/element.rb +11 -8
- data/lib/capybara/node/finders.rb +5 -1
- data/lib/capybara/node/matchers.rb +24 -15
- data/lib/capybara/node/simple.rb +1 -1
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/rack_test/node.rb +34 -9
- data/lib/capybara/result.rb +24 -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 +2 -2
- 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 +2 -0
- data/lib/capybara/selector/definition/label.rb +1 -1
- data/lib/capybara/selector/definition/select.rb +31 -12
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
- data/lib/capybara/selenium/extensions/html5_drag.rb +24 -8
- data/lib/capybara/selenium/node.rb +23 -6
- data/lib/capybara/selenium/nodes/chrome_node.rb +4 -2
- data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
- data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
- data/lib/capybara/session.rb +30 -15
- data/lib/capybara/spec/public/test.js +40 -6
- data/lib/capybara/spec/session/all_spec.rb +45 -5
- data/lib/capybara/spec/session/assert_text_spec.rb +5 -5
- data/lib/capybara/spec/session/fill_in_spec.rb +20 -0
- data/lib/capybara/spec/session/has_css_spec.rb +3 -3
- data/lib/capybara/spec/session/has_select_spec.rb +28 -0
- data/lib/capybara/spec/session/has_text_spec.rb +5 -1
- data/lib/capybara/spec/session/node_spec.rb +92 -3
- data/lib/capybara/spec/views/form.erb +6 -1
- data/lib/capybara/version.rb +1 -1
- data/spec/rack_test_spec.rb +0 -1
- data/spec/result_spec.rb +4 -0
- data/spec/selenium_spec_chrome.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd31d35629d475d7fdaba1d6e415599d995a08f27b28fa619a3a4449b61b91d8
|
4
|
+
data.tar.gz: 27c812629e2d99e8f4c62fa7961df9b499c5346b1c61092faf487f592356033d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 946e3f2de0137ddaa6e3a2febba2c87244997737c54a10024133de110ca41b8aeddcb66e0437bef5d826e9fe21d4c42701674c3864bd578d24c30c7b1f90e2a9
|
7
|
+
data.tar.gz: f9409de3e2e0ea44e0bb6b6f77cce7e0e8f5a4d95c43fb62af2eb63d11e755d6a8c00b9b9b4d2bbe2729538d0d1038e92468e0a7994d1578b50e05b5227b87f4
|
data/History.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
# Version 3.31.0
|
2
|
+
Release date: 2020-01-26
|
3
|
+
|
4
|
+
### Added
|
5
|
+
|
6
|
+
* Support setting range inputs with the selenium driver [Andrew White]
|
7
|
+
* Support setting range inputs with the rack driver
|
8
|
+
* Support drop modifier keys in drag & drop [Elliot Crosby-McCullough]
|
9
|
+
* `enabled_options` and `disabled options` filters for select selector
|
10
|
+
* Support beginless ranges
|
11
|
+
* Optionally allow `all` results to be reloaded when stable - Beta feature - may be removed in
|
12
|
+
future version if problems occur
|
13
|
+
|
14
|
+
### Fixed
|
15
|
+
|
16
|
+
* Fix Ruby 2.7 deprecation notices around keyword arguments. I have tried to do this without
|
17
|
+
any breaking changes, but due to the nature of the 2.7 changes and some selector types accepting
|
18
|
+
Hashes as locators there are a lot of edge cases. If you find any broken cases please report
|
19
|
+
them and I'll see if they're fixable.
|
20
|
+
* Clicking on details/summary element behavior in rack_test driver_
|
21
|
+
|
1
22
|
# Version 3.30.0
|
2
23
|
Release date: 2019-12-24
|
3
24
|
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
8
|
[![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=capybara&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
|
9
9
|
|
10
|
-
**Note** You are viewing the README for the 3.
|
10
|
+
**Note** You are viewing the README for the 3.31.x stable branch of Capybara.
|
11
11
|
|
12
12
|
Capybara helps you test web applications by simulating how a real user would
|
13
13
|
interact with your app. It is agnostic about the driver running your tests and
|
data/lib/capybara/dsl.rb
CHANGED
@@ -47,8 +47,16 @@ module Capybara
|
|
47
47
|
end
|
48
48
|
|
49
49
|
Session::DSL_METHODS.each do |method|
|
50
|
-
|
51
|
-
|
50
|
+
if RUBY_VERSION >= '2.7'
|
51
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
52
|
+
def #{method}(...)
|
53
|
+
page.method("#{method}").call(...)
|
54
|
+
end
|
55
|
+
METHOD
|
56
|
+
else
|
57
|
+
define_method method do |*args, &block|
|
58
|
+
page.send method, *args, &block
|
59
|
+
end
|
52
60
|
end
|
53
61
|
end
|
54
62
|
end
|
data/lib/capybara/minitest.rb
CHANGED
@@ -52,6 +52,7 @@ module Capybara
|
|
52
52
|
raise ::Minitest::Assertion, e.message
|
53
53
|
end
|
54
54
|
ASSERTION
|
55
|
+
ruby2_keywords "assert_#{assertion_name}" if respond_to?(:ruby2_keywords)
|
55
56
|
end
|
56
57
|
|
57
58
|
alias_method :refute_title, :assert_no_title
|
@@ -109,6 +110,7 @@ module Capybara
|
|
109
110
|
raise ::Minitest::Assertion, e.message
|
110
111
|
end
|
111
112
|
ASSERTION
|
113
|
+
ruby2_keywords "assert_#{assertion_name}" if respond_to?(:ruby2_keywords)
|
112
114
|
end
|
113
115
|
|
114
116
|
alias_method :refute_selector, :assert_no_selector
|
@@ -120,14 +122,16 @@ module Capybara
|
|
120
122
|
define_method "assert_#{selector_type}" do |*args, &optional_filter_block|
|
121
123
|
subject, args = determine_subject(args)
|
122
124
|
locator, options = extract_locator(args)
|
123
|
-
assert_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
|
125
|
+
assert_selector(subject, selector_type.to_sym, locator, **options, &optional_filter_block)
|
124
126
|
end
|
127
|
+
ruby2_keywords "assert_#{selector_type}" if respond_to?(:ruby2_keywords)
|
125
128
|
|
126
129
|
define_method "assert_no_#{selector_type}" do |*args, &optional_filter_block|
|
127
130
|
subject, args = determine_subject(args)
|
128
131
|
locator, options = extract_locator(args)
|
129
|
-
assert_no_selector(subject, selector_type.to_sym, locator, options, &optional_filter_block)
|
132
|
+
assert_no_selector(subject, selector_type.to_sym, locator, **options, &optional_filter_block)
|
130
133
|
end
|
134
|
+
ruby2_keywords "assert_no_#{selector_type}" if respond_to?(:ruby2_keywords)
|
131
135
|
alias_method "refute_#{selector_type}", "assert_no_#{selector_type}"
|
132
136
|
end
|
133
137
|
|
@@ -135,14 +139,22 @@ module Capybara
|
|
135
139
|
define_method "assert_#{field_type}_field" do |*args, &optional_filter_block|
|
136
140
|
subject, args = determine_subject(args)
|
137
141
|
locator, options = extract_locator(args)
|
138
|
-
assert_selector(subject, :field, locator, options.merge(field_type.to_sym => true), &optional_filter_block)
|
142
|
+
assert_selector(subject, :field, locator, **options.merge(field_type.to_sym => true), &optional_filter_block)
|
139
143
|
end
|
144
|
+
ruby2_keywords "assert_#{field_type}_field" if respond_to?(:ruby2_keywords)
|
140
145
|
|
141
146
|
define_method "assert_no_#{field_type}_field" do |*args, &optional_filter_block|
|
142
147
|
subject, args = determine_subject(args)
|
143
148
|
locator, options = extract_locator(args)
|
144
|
-
assert_no_selector(
|
149
|
+
assert_no_selector(
|
150
|
+
subject,
|
151
|
+
:field,
|
152
|
+
locator,
|
153
|
+
**options.merge(field_type.to_sym => true),
|
154
|
+
&optional_filter_block
|
155
|
+
)
|
145
156
|
end
|
157
|
+
ruby2_keywords "assert_no_#{field_type}_field" if respond_to?(:ruby2_keywords)
|
146
158
|
alias_method "refute_#{field_type}_field", "assert_no_#{field_type}_field"
|
147
159
|
end
|
148
160
|
|
@@ -151,11 +163,13 @@ module Capybara
|
|
151
163
|
subject, args = determine_subject(args)
|
152
164
|
assert_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
|
153
165
|
end
|
166
|
+
ruby2_keywords "assert_matches_#{selector_type}" if respond_to?(:ruby2_keywords)
|
154
167
|
|
155
168
|
define_method "assert_not_matches_#{selector_type}" do |*args, &optional_filter_block|
|
156
169
|
subject, args = determine_subject(args)
|
157
170
|
assert_not_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)
|
158
171
|
end
|
172
|
+
ruby2_keywords "assert_not_matches_#{selector_type}" if respond_to?(:ruby2_keywords)
|
159
173
|
alias_method "refute_matches_#{selector_type}", "assert_not_matches_#{selector_type}"
|
160
174
|
end
|
161
175
|
|
@@ -27,9 +27,11 @@ module Capybara
|
|
27
27
|
@query_scope = query_scope
|
28
28
|
@query = query
|
29
29
|
@allow_reload = false
|
30
|
+
@query_idx = nil
|
30
31
|
end
|
31
32
|
|
32
|
-
def allow_reload!
|
33
|
+
def allow_reload!(idx = nil)
|
34
|
+
@query_idx = idx
|
33
35
|
@allow_reload = true
|
34
36
|
end
|
35
37
|
|
@@ -407,6 +409,8 @@ module Capybara
|
|
407
409
|
# @option options [Boolean] :html5 When using Chrome/Firefox with Selenium enables to force the use of HTML5
|
408
410
|
# (true) or legacy (false) dragging. If not specified the driver will attempt to
|
409
411
|
# detect the correct method to use.
|
412
|
+
# @option options [Array<Symbol>,Symbol] :drop_modifiers Modifier keys which should be held while the dragged element is dropped.
|
413
|
+
#
|
410
414
|
#
|
411
415
|
# @return [Capybara::Node::Element] The dragged element
|
412
416
|
def drag_to(node, **options)
|
@@ -545,14 +549,13 @@ module Capybara
|
|
545
549
|
|
546
550
|
# @api private
|
547
551
|
def reload
|
548
|
-
|
549
|
-
begin
|
550
|
-
reloaded = @query.resolve_for(query_scope.reload)&.first
|
552
|
+
return self unless @allow_reload
|
551
553
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
554
|
+
begin
|
555
|
+
reloaded = @query.resolve_for(query_scope.reload)[@query_idx.to_i]
|
556
|
+
@base = reloaded.base if reloaded
|
557
|
+
rescue StandardError => e
|
558
|
+
raise e unless catch_error?(e)
|
556
559
|
end
|
557
560
|
self
|
558
561
|
end
|
@@ -235,13 +235,16 @@ module Capybara
|
|
235
235
|
# @option options [Integer] maximum Maximum number of matches that are expected to be found
|
236
236
|
# @option options [Integer] minimum Minimum number of matches that are expected to be found
|
237
237
|
# @option options [Range] between Number of matches found must be within the given range
|
238
|
+
# @option options [Boolean] allow_reload Beta feature - May be removed in any version.
|
239
|
+
# When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
|
240
|
+
# if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
|
238
241
|
# @overload all([kind = Capybara.default_selector], locator = nil, **options)
|
239
242
|
# @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
|
240
243
|
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
|
241
244
|
# @yieldreturn [Boolean] Should the element be considered in the results?
|
242
245
|
# @return [Capybara::Result] A collection of found elements
|
243
246
|
# @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
|
244
|
-
def all(*args, **options, &optional_filter_block)
|
247
|
+
def all(*args, allow_reload: false, **options, &optional_filter_block)
|
245
248
|
minimum_specified = options_include_minimum?(options)
|
246
249
|
options = { minimum: 1 }.merge(options) unless minimum_specified
|
247
250
|
options[:session_options] = session_options
|
@@ -250,6 +253,7 @@ module Capybara
|
|
250
253
|
begin
|
251
254
|
synchronize(query.wait) do
|
252
255
|
result = query.resolve_for(self)
|
256
|
+
result.allow_reload! if allow_reload
|
253
257
|
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
254
258
|
|
255
259
|
result
|
@@ -61,7 +61,7 @@ module Capybara
|
|
61
61
|
# @return [Boolean] If the styles match
|
62
62
|
#
|
63
63
|
def matches_style?(styles, **options)
|
64
|
-
make_predicate(options) { assert_matches_style(styles, options) }
|
64
|
+
make_predicate(options) { assert_matches_style(styles, **options) }
|
65
65
|
end
|
66
66
|
|
67
67
|
##
|
@@ -123,8 +123,8 @@ module Capybara
|
|
123
123
|
# @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
|
124
124
|
#
|
125
125
|
def assert_matches_style(styles, **options)
|
126
|
-
query_args = _set_query_session_options(styles,
|
127
|
-
query = Capybara::Queries::StyleQuery.new(*query_args)
|
126
|
+
query_args, query_opts = _set_query_session_options(styles, options)
|
127
|
+
query = Capybara::Queries::StyleQuery.new(*query_args, **query_opts)
|
128
128
|
synchronize(query.wait) do
|
129
129
|
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
130
130
|
end
|
@@ -672,8 +672,8 @@ module Capybara
|
|
672
672
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
673
673
|
# @return [true]
|
674
674
|
#
|
675
|
-
def assert_text(*args)
|
676
|
-
_verify_text(*args) do |count, query|
|
675
|
+
def assert_text(type_or_text, *args, **opts)
|
676
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
677
677
|
unless query.matches_count?(count) && (count.positive? || query.expects_none?)
|
678
678
|
raise Capybara::ExpectationNotMet, query.failure_message
|
679
679
|
end
|
@@ -688,8 +688,8 @@ module Capybara
|
|
688
688
|
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
689
689
|
# @return [true]
|
690
690
|
#
|
691
|
-
def assert_no_text(*args)
|
692
|
-
_verify_text(*args) do |count, query|
|
691
|
+
def assert_no_text(type_or_text, *args, **opts)
|
692
|
+
_verify_text(type_or_text, *args, **opts) do |count, query|
|
693
693
|
if query.matches_count?(count) && (count.positive? || query.expects_none?)
|
694
694
|
raise Capybara::ExpectationNotMet, query.negative_failure_message
|
695
695
|
end
|
@@ -711,7 +711,7 @@ module Capybara
|
|
711
711
|
# @return [Boolean] Whether it exists
|
712
712
|
#
|
713
713
|
def has_text?(*args, **options)
|
714
|
-
make_predicate(options) { assert_text(*args, options) }
|
714
|
+
make_predicate(options) { assert_text(*args, **options) }
|
715
715
|
end
|
716
716
|
alias_method :has_content?, :has_text?
|
717
717
|
|
@@ -723,7 +723,7 @@ module Capybara
|
|
723
723
|
# @return [Boolean] Whether it doesn't exist
|
724
724
|
#
|
725
725
|
def has_no_text?(*args, **options)
|
726
|
-
make_predicate(options) { assert_no_text(*args, options) }
|
726
|
+
make_predicate(options) { assert_no_text(*args, **options) }
|
727
727
|
end
|
728
728
|
alias_method :has_no_content?, :has_no_text?
|
729
729
|
|
@@ -832,8 +832,14 @@ module Capybara
|
|
832
832
|
end
|
833
833
|
|
834
834
|
def _verify_selector_result(query_args, optional_filter_block, query_type = Capybara::Queries::SelectorQuery)
|
835
|
-
query_args =
|
836
|
-
|
835
|
+
# query_args, query_opts = if query_args[0].is_a? Symbol
|
836
|
+
# a,o = _set_query_session_options(*query_args.slice(2..))
|
837
|
+
# [query_args.slice(0..1).concat(a), o]
|
838
|
+
# else
|
839
|
+
# _set_query_session_options(*query_args)
|
840
|
+
# end
|
841
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
842
|
+
query = query_type.new(*query_args, **query_opts, &optional_filter_block)
|
837
843
|
synchronize(query.wait) do
|
838
844
|
yield query.resolve_for(self), query
|
839
845
|
end
|
@@ -841,8 +847,8 @@ module Capybara
|
|
841
847
|
end
|
842
848
|
|
843
849
|
def _verify_match_result(query_args, optional_filter_block)
|
844
|
-
query_args = _set_query_session_options(*query_args)
|
845
|
-
query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
|
850
|
+
query_args, query_opts = _set_query_session_options(*query_args)
|
851
|
+
query = Capybara::Queries::MatchQuery.new(*query_args, **query_opts, &optional_filter_block)
|
846
852
|
synchronize(query.wait) do
|
847
853
|
yield query.resolve_for(parent || session&.document || query_scope)
|
848
854
|
end
|
@@ -858,9 +864,12 @@ module Capybara
|
|
858
864
|
true
|
859
865
|
end
|
860
866
|
|
861
|
-
def _set_query_session_options(*query_args
|
867
|
+
def _set_query_session_options(*query_args)
|
868
|
+
query_args, query_options = query_args.dup, {}
|
869
|
+
# query_options = query_args.pop if query_options.empty? && query_args.last.is_a?(Hash)
|
870
|
+
query_options = query_args.pop if query_args.last.is_a?(Hash)
|
862
871
|
query_options[:session_options] = session_options
|
863
|
-
query_args
|
872
|
+
[query_args, query_options]
|
864
873
|
end
|
865
874
|
|
866
875
|
def make_predicate(options)
|
data/lib/capybara/node/simple.rb
CHANGED
@@ -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
|
@@ -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)[
|
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,11 @@ 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 -= 1 if max && idx.exclude_end?
|
67
|
+
max
|
63
68
|
end
|
64
69
|
|
65
70
|
if max_idx.nil?
|
@@ -94,7 +99,9 @@ module Capybara
|
|
94
99
|
end
|
95
100
|
|
96
101
|
if between
|
97
|
-
min, max = between.
|
102
|
+
min, max = (between.begin && between.min) || 1, between.end
|
103
|
+
max -= 1 if max && between.exclude_end?
|
104
|
+
|
98
105
|
size = load_up_to(max ? max + 1 : min)
|
99
106
|
return size <=> min unless between.include?(size)
|
100
107
|
end
|
@@ -130,13 +137,26 @@ module Capybara
|
|
130
137
|
@elements.length
|
131
138
|
end
|
132
139
|
|
140
|
+
##
|
141
|
+
# @api private
|
142
|
+
#
|
143
|
+
def allow_reload!
|
144
|
+
@allow_reload = true
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
133
148
|
private
|
134
149
|
|
150
|
+
def add_to_cache(elem)
|
151
|
+
elem.allow_reload!(@result_cache.size) if @allow_reload
|
152
|
+
@result_cache << elem
|
153
|
+
end
|
154
|
+
|
135
155
|
def load_up_to(num)
|
136
156
|
loop do
|
137
157
|
break if @result_cache.size >= num
|
138
158
|
|
139
|
-
@
|
159
|
+
add_to_cache(@results_enum.next)
|
140
160
|
end
|
141
161
|
@result_cache.size
|
142
162
|
end
|