capybara 3.6.0 → 3.7.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 -1
- data/lib/capybara.rb +2 -0
- data/lib/capybara/minitest/spec.rb +1 -1
- data/lib/capybara/node/actions.rb +34 -25
- data/lib/capybara/node/base.rb +15 -17
- data/lib/capybara/node/document_matchers.rb +1 -3
- data/lib/capybara/node/element.rb +11 -12
- data/lib/capybara/node/finders.rb +2 -1
- data/lib/capybara/node/simple.rb +13 -6
- data/lib/capybara/queries/base_query.rb +4 -4
- data/lib/capybara/queries/selector_query.rb +119 -94
- data/lib/capybara/queries/text_query.rb +2 -1
- data/lib/capybara/rack_test/form.rb +4 -4
- data/lib/capybara/rack_test/node.rb +5 -5
- data/lib/capybara/result.rb +23 -32
- data/lib/capybara/rspec/compound.rb +1 -1
- data/lib/capybara/rspec/matchers.rb +63 -61
- data/lib/capybara/selector.rb +28 -10
- data/lib/capybara/selector/css.rb +17 -17
- data/lib/capybara/selector/filter_set.rb +9 -9
- data/lib/capybara/selector/selector.rb +3 -4
- data/lib/capybara/selenium/driver.rb +73 -95
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +4 -4
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +9 -0
- data/lib/capybara/selenium/node.rb +127 -67
- data/lib/capybara/selenium/nodes/chrome_node.rb +3 -3
- data/lib/capybara/selenium/nodes/marionette_node.rb +14 -8
- data/lib/capybara/server.rb +2 -2
- data/lib/capybara/server/animation_disabler.rb +17 -3
- data/lib/capybara/server/middleware.rb +8 -4
- data/lib/capybara/session.rb +43 -37
- data/lib/capybara/session/config.rb +8 -6
- data/lib/capybara/spec/session/assert_text_spec.rb +14 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +7 -0
- data/lib/capybara/spec/session/check_spec.rb +21 -0
- data/lib/capybara/spec/session/choose_spec.rb +15 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +7 -0
- data/lib/capybara/spec/session/find_spec.rb +2 -1
- data/lib/capybara/spec/session/has_selector_spec.rb +18 -0
- data/lib/capybara/spec/session/has_text_spec.rb +14 -0
- data/lib/capybara/spec/session/node_spec.rb +2 -1
- data/lib/capybara/spec/session/reset_session_spec.rb +4 -4
- data/lib/capybara/spec/session/text_spec.rb +2 -1
- data/lib/capybara/spec/session/title_spec.rb +2 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +8 -0
- data/lib/capybara/spec/session/within_spec.rb +2 -1
- data/lib/capybara/spec/spec_helper.rb +1 -32
- data/lib/capybara/spec/views/with_js.erb +3 -4
- data/lib/capybara/version.rb +1 -1
- data/spec/minitest_spec.rb +4 -0
- data/spec/minitest_spec_spec.rb +4 -0
- data/spec/rack_test_spec.rb +4 -4
- data/spec/rspec/shared_spec_matchers.rb +4 -2
- data/spec/selector_spec.rb +15 -1
- data/spec/selenium_spec_chrome.rb +1 -6
- data/spec/selenium_spec_chrome_remote.rb +1 -1
- data/spec/selenium_spec_firefox_remote.rb +2 -5
- data/spec/selenium_spec_ie.rb +41 -4
- data/spec/selenium_spec_marionette.rb +1 -25
- data/spec/shared_selenium_session.rb +74 -16
- data/spec/spec_helper.rb +41 -0
- metadata +2 -2
@@ -3,9 +3,8 @@
|
|
3
3
|
module Capybara
|
4
4
|
module Queries
|
5
5
|
class SelectorQuery < Queries::BaseQuery
|
6
|
-
|
7
|
-
|
8
|
-
VALID_KEYS = COUNT_KEYS + %i[text id class visible exact exact_text match wait filter_set]
|
6
|
+
attr_reader :expression, :selector, :locator, :options
|
7
|
+
VALID_KEYS = COUNT_KEYS + %i[text id class visible exact exact_text normalize_ws match wait filter_set]
|
9
8
|
VALID_MATCH = %i[first smart prefer_exact one].freeze
|
10
9
|
|
11
10
|
def initialize(*args,
|
@@ -25,7 +24,7 @@ module Capybara
|
|
25
24
|
|
26
25
|
raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
|
27
26
|
|
28
|
-
@expression =
|
27
|
+
@expression = selector.call(@locator, @options.merge(selector_config: { enable_aria_label: enable_aria_label, test_id: test_id }))
|
29
28
|
|
30
29
|
warn_exact_usage
|
31
30
|
|
@@ -36,22 +35,22 @@ module Capybara
|
|
36
35
|
def label; selector.label || selector.name; end
|
37
36
|
|
38
37
|
def description(applied = false)
|
39
|
-
|
40
|
-
if !applied ||
|
41
|
-
|
42
|
-
|
38
|
+
desc = +''
|
39
|
+
if !applied || applied_filters
|
40
|
+
desc << 'visible ' if visible == :visible
|
41
|
+
desc << 'non-visible ' if visible == :hidden
|
43
42
|
end
|
44
|
-
|
45
|
-
if !applied ||
|
46
|
-
|
47
|
-
|
43
|
+
desc << "#{label} #{locator.inspect}"
|
44
|
+
if !applied || applied_filters
|
45
|
+
desc << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
|
46
|
+
desc << " with exact text #{exact_text}" if exact_text.is_a?(String)
|
48
47
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
48
|
+
desc << " with id #{options[:id]}" if options[:id]
|
49
|
+
desc << " with classes [#{Array(options[:class]).join(',')}]" if options[:class]
|
50
|
+
desc << selector.description(node_filters: !applied || (applied_filters == :node), **options)
|
51
|
+
desc << ' that also matches the custom filter block' if @filter_block && (!applied || (applied_filters == :node))
|
52
|
+
desc << " within #{@resolved_node.inspect}" if describe_within?
|
53
|
+
desc
|
55
54
|
end
|
56
55
|
|
57
56
|
def applied_description
|
@@ -59,15 +58,9 @@ module Capybara
|
|
59
58
|
end
|
60
59
|
|
61
60
|
def matches_filters?(node)
|
61
|
+
return true if (@resolved_node&.== node) && options[:allow_self]
|
62
62
|
@applied_filters ||= :system
|
63
|
-
return false
|
64
|
-
return false if exact_text.is_a?(String) && !matches_exact_text_filter(node, exact_text)
|
65
|
-
|
66
|
-
case visible
|
67
|
-
when :visible then return false unless node.visible?
|
68
|
-
when :hidden then return false if node.visible?
|
69
|
-
end
|
70
|
-
|
63
|
+
return false unless matches_text_filter?(node) && matches_exact_text_filter?(node) && matches_visible_filter?(node)
|
71
64
|
@applied_filters = :node
|
72
65
|
matches_node_filters?(node) && matches_filter_block?(node)
|
73
66
|
rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : [])
|
@@ -106,17 +99,7 @@ module Capybara
|
|
106
99
|
@applied_filters = false
|
107
100
|
@resolved_node = node
|
108
101
|
node.synchronize do
|
109
|
-
children =
|
110
|
-
node.find_css(css)
|
111
|
-
else
|
112
|
-
node.find_xpath(xpath(exact))
|
113
|
-
end.map do |child|
|
114
|
-
if node.is_a?(Capybara::Node::Base)
|
115
|
-
Capybara::Node::Element.new(node.session, child, node, self)
|
116
|
-
else
|
117
|
-
Capybara::Node::Simple.new(child)
|
118
|
-
end
|
119
|
-
end
|
102
|
+
children = find_nodes_by_selector_format(node, exact).map(&method(:to_element))
|
120
103
|
Capybara::Result.new(children, self)
|
121
104
|
end
|
122
105
|
end
|
@@ -136,15 +119,35 @@ module Capybara
|
|
136
119
|
|
137
120
|
private
|
138
121
|
|
122
|
+
def applied_filters
|
123
|
+
@applied_filters ||= false
|
124
|
+
end
|
125
|
+
|
139
126
|
def find_selector(locator)
|
140
127
|
selector = if locator.is_a?(Symbol)
|
141
128
|
Selector.all.fetch(locator) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
|
142
129
|
else
|
143
|
-
Selector.all.values.find { |
|
130
|
+
Selector.all.values.find { |sel| sel.match?(locator) }
|
144
131
|
end
|
145
132
|
selector || Selector.all[session_options.default_selector]
|
146
133
|
end
|
147
134
|
|
135
|
+
def find_nodes_by_selector_format(node, exact)
|
136
|
+
if selector.format == :css
|
137
|
+
node.find_css(css)
|
138
|
+
else
|
139
|
+
node.find_xpath(xpath(exact))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_element(node)
|
144
|
+
if @resolved_node.is_a?(Capybara::Node::Base)
|
145
|
+
Capybara::Node::Element.new(@resolved_node.session, node, @resolved_node, self)
|
146
|
+
else
|
147
|
+
Capybara::Node::Simple.new(node)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
148
151
|
def valid_keys
|
149
152
|
VALID_KEYS + custom_keys
|
150
153
|
end
|
@@ -171,7 +174,6 @@ module Capybara
|
|
171
174
|
|
172
175
|
def matches_filter_block?(node)
|
173
176
|
return true unless @filter_block
|
174
|
-
|
175
177
|
if node.respond_to?(:session)
|
176
178
|
node.session.using_wait_time(0) { @filter_block.call(node) }
|
177
179
|
else
|
@@ -201,87 +203,91 @@ module Capybara
|
|
201
203
|
unless VALID_MATCH.include?(match)
|
202
204
|
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
|
203
205
|
end
|
204
|
-
unhandled_options = @options.keys
|
205
|
-
|
206
|
-
|
206
|
+
unhandled_options = @options.keys.reject do |option_name|
|
207
|
+
valid_keys.include?(option_name) ||
|
208
|
+
expression_filters.any? { |_name, ef| ef.handles_option? option_name } ||
|
207
209
|
node_filters.any? { |_name, nf| nf.handles_option? option_name }
|
208
210
|
end
|
209
211
|
|
210
212
|
return if unhandled_options.empty?
|
211
213
|
invalid_names = unhandled_options.map(&:inspect).join(', ')
|
212
|
-
valid_names = valid_keys.map(&:inspect).join(', ')
|
214
|
+
valid_names = (valid_keys - [:allow_self]).map(&:inspect).join(', ')
|
213
215
|
raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
|
214
216
|
end
|
215
217
|
|
216
218
|
def filtered_xpath(expr)
|
217
|
-
if
|
218
|
-
|
219
|
-
|
219
|
+
if use_default_id_filter?
|
220
|
+
id_xpath = if options[:id].is_a? XPath::Expression
|
221
|
+
XPath.attr(:id)[options[:id]]
|
220
222
|
else
|
221
|
-
|
223
|
+
XPath.attr(:id) == options[:id]
|
222
224
|
end
|
225
|
+
expr = "(#{expr})[#{id_xpath}]"
|
223
226
|
end
|
224
|
-
|
225
|
-
class_xpath = if options[:class].is_a?(XPath::Expression)
|
226
|
-
XPath.attr(:class)[options[:class]]
|
227
|
-
else
|
228
|
-
Array(options[:class]).map do |klass|
|
229
|
-
if klass.start_with?('!')
|
230
|
-
!XPath.attr(:class).contains_word(klass.slice(1))
|
231
|
-
else
|
232
|
-
XPath.attr(:class).contains_word(klass)
|
233
|
-
end
|
234
|
-
end.reduce(:&)
|
235
|
-
end
|
236
|
-
expr = "(#{expr})[#{class_xpath}]"
|
237
|
-
end
|
227
|
+
expr = "(#{expr})[#{xpath_from_classes}]" if use_default_class_filter?
|
238
228
|
expr
|
239
229
|
end
|
240
230
|
|
241
231
|
def filtered_css(expr)
|
242
|
-
|
243
|
-
|
232
|
+
::Capybara::Selector::CSS.split(expr).map do |sel|
|
233
|
+
sel += css_from_id if use_default_id_filter?
|
234
|
+
sel += css_from_classes if use_default_class_filter?
|
235
|
+
sel
|
236
|
+
end.join(', ')
|
237
|
+
end
|
244
238
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
239
|
+
def use_default_id_filter?
|
240
|
+
options.key?(:id) && !custom_keys.include?(:id)
|
241
|
+
end
|
242
|
+
|
243
|
+
def use_default_class_filter?
|
244
|
+
options.key?(:class) && !custom_keys.include?(:class)
|
245
|
+
end
|
246
|
+
|
247
|
+
def css_from_classes
|
248
|
+
if options[:class].is_a?(XPath::Expression)
|
249
249
|
raise ArgumentError, 'XPath expressions are not supported for the :class filter with CSS based selectors'
|
250
250
|
end
|
251
251
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
sel
|
257
|
-
end.join(', ')
|
258
|
-
end
|
252
|
+
classes = Array(options[:class]).group_by { |cl| cl.start_with? '!' }
|
253
|
+
(classes[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl)}" } +
|
254
|
+
classes[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1))})" }).join
|
255
|
+
end
|
259
256
|
|
260
|
-
|
257
|
+
def css_from_id
|
258
|
+
if options[:id].is_a?(XPath::Expression)
|
259
|
+
raise ArgumentError, 'XPath expressions are not supported for the :id filter with CSS based selectors'
|
260
|
+
end
|
261
|
+
"##{::Capybara::Selector::CSS.escape(options[:id])}"
|
261
262
|
end
|
262
263
|
|
263
|
-
def
|
264
|
-
|
265
|
-
|
266
|
-
|
264
|
+
def xpath_from_classes
|
265
|
+
return XPath.attr(:class)[options[:class]] if options[:class].is_a?(XPath::Expression)
|
266
|
+
|
267
|
+
Array(options[:class]).map do |klass|
|
268
|
+
if klass.start_with?('!')
|
269
|
+
!XPath.attr(:class).contains_word(klass.slice(1))
|
270
|
+
else
|
271
|
+
XPath.attr(:class).contains_word(klass)
|
272
|
+
end
|
273
|
+
end.reduce(:&)
|
267
274
|
end
|
268
275
|
|
269
|
-
def apply_expression_filters(
|
276
|
+
def apply_expression_filters(expression)
|
270
277
|
unapplied_options = options.keys - valid_keys
|
271
|
-
expression_filters.inject(
|
278
|
+
expression_filters.inject(expression) do |expr, (name, ef)|
|
272
279
|
if ef.matcher?
|
273
|
-
unapplied_options.select { |option_name| ef.handles_option?(option_name) }.
|
280
|
+
unapplied_options.select { |option_name| ef.handles_option?(option_name) }.inject(expr) do |memo, option_name|
|
274
281
|
unapplied_options.delete(option_name)
|
275
|
-
|
282
|
+
ef.apply_filter(memo, option_name, options[option_name])
|
276
283
|
end
|
277
|
-
memo
|
278
284
|
elsif options.key?(name)
|
279
285
|
unapplied_options.delete(name)
|
280
|
-
ef.apply_filter(
|
286
|
+
ef.apply_filter(expr, name, options[name])
|
281
287
|
elsif ef.default?
|
282
|
-
ef.apply_filter(
|
288
|
+
ef.apply_filter(expr, name, ef.default)
|
283
289
|
else
|
284
|
-
|
290
|
+
expr
|
285
291
|
end
|
286
292
|
end
|
287
293
|
end
|
@@ -307,21 +313,40 @@ module Capybara
|
|
307
313
|
node.is_a?(::Capybara::Node::Simple) && node.path == '/'
|
308
314
|
end
|
309
315
|
|
310
|
-
def matches_text_filter(node
|
311
|
-
|
316
|
+
def matches_text_filter?(node)
|
317
|
+
value = options[:text]
|
318
|
+
return true unless value
|
319
|
+
return matches_text_exactly?(node, value) if exact_text == true
|
312
320
|
regexp = value.is_a?(Regexp) ? value : Regexp.escape(value.to_s)
|
313
|
-
matches_text_regexp(node, regexp)
|
321
|
+
matches_text_regexp?(node, regexp)
|
314
322
|
end
|
315
323
|
|
316
|
-
def matches_exact_text_filter(node
|
324
|
+
def matches_exact_text_filter?(node)
|
325
|
+
return true unless exact_text.is_a?(String)
|
326
|
+
matches_text_exactly?(node, exact_text)
|
327
|
+
end
|
328
|
+
|
329
|
+
def matches_visible_filter?(node)
|
330
|
+
case visible
|
331
|
+
when :visible then node.visible?
|
332
|
+
when :hidden then !node.visible?
|
333
|
+
else true
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def matches_text_exactly?(node, value)
|
317
338
|
regexp = value.is_a?(Regexp) ? value : /\A#{Regexp.escape(value.to_s)}\z/
|
318
|
-
matches_text_regexp(node, regexp)
|
339
|
+
matches_text_regexp?(node, regexp)
|
340
|
+
end
|
341
|
+
|
342
|
+
def normalize_ws
|
343
|
+
options.fetch(:normalize_ws, session_options.default_normalize_ws)
|
319
344
|
end
|
320
345
|
|
321
|
-
def matches_text_regexp(node, regexp)
|
346
|
+
def matches_text_regexp?(node, regexp)
|
322
347
|
text_visible = visible
|
323
348
|
text_visible = :all if text_visible == :hidden
|
324
|
-
node.text(text_visible).match(regexp)
|
349
|
+
!!node.text(text_visible, normalize_ws: normalize_ws).match(regexp)
|
325
350
|
end
|
326
351
|
end
|
327
352
|
end
|
@@ -90,7 +90,8 @@ module Capybara
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def text(node: @node, query_type: @type)
|
93
|
-
|
93
|
+
normalize_ws = options.fetch(:normalize_ws, session_options.default_normalize_ws)
|
94
|
+
node.text(query_type, normalize_ws: normalize_ws)
|
94
95
|
end
|
95
96
|
|
96
97
|
def default_type
|
@@ -22,10 +22,10 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
22
22
|
params = make_params
|
23
23
|
|
24
24
|
form_element_types = %i[input select textarea]
|
25
|
-
form_elements_xpath = XPath.generate do |
|
26
|
-
xpath =
|
27
|
-
xpath +=
|
28
|
-
xpath.where(!
|
25
|
+
form_elements_xpath = XPath.generate do |xp|
|
26
|
+
xpath = xp.descendant(*form_element_types).where(!xp.attr(:form))
|
27
|
+
xpath += xp.anywhere(*form_element_types).where(xp.attr(:form) == native[:id]) if native[:id]
|
28
|
+
xpath.where(!xp.attr(:disabled))
|
29
29
|
end.to_s
|
30
30
|
|
31
31
|
native.xpath(form_elements_xpath).map do |field|
|
@@ -105,11 +105,11 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def find_xpath(locator)
|
108
|
-
native.xpath(locator).map { |
|
108
|
+
native.xpath(locator).map { |el| self.class.new(driver, el) }
|
109
109
|
end
|
110
110
|
|
111
111
|
def find_css(locator)
|
112
|
-
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |
|
112
|
+
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |el| self.class.new(driver, el) }
|
113
113
|
end
|
114
114
|
|
115
115
|
def ==(other)
|
@@ -165,7 +165,7 @@ private
|
|
165
165
|
end
|
166
166
|
|
167
167
|
def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
|
168
|
-
other_radios_xpath = XPath.generate { |
|
168
|
+
other_radios_xpath = XPath.generate { |xp| xp.anywhere(:input)[xp.attr(:name) == self[:name]] }.to_s
|
169
169
|
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute('checked') }
|
170
170
|
native['checked'] = 'checked'
|
171
171
|
end
|
@@ -185,11 +185,11 @@ private
|
|
185
185
|
value = value.to_s[0...self[:maxlength].to_i]
|
186
186
|
end
|
187
187
|
if value.is_a?(Array) # Assert multiple attribute is present
|
188
|
-
value.each do |
|
188
|
+
value.each do |val|
|
189
189
|
new_native = native.clone
|
190
190
|
new_native.remove_attribute('value')
|
191
191
|
native.add_next_sibling(new_native)
|
192
|
-
new_native['value'] =
|
192
|
+
new_native['value'] = val.to_s
|
193
193
|
end
|
194
194
|
native.remove
|
195
195
|
else
|
data/lib/capybara/result.rb
CHANGED
@@ -62,10 +62,7 @@ module Capybara
|
|
62
62
|
if max_idx.nil?
|
63
63
|
full_results[*args]
|
64
64
|
else
|
65
|
-
|
66
|
-
break if @result_cache.size > max_idx
|
67
|
-
@result_cache << @results_enum.next
|
68
|
-
end
|
65
|
+
load_up_to(max_idx + 1)
|
69
66
|
@result_cache[*args]
|
70
67
|
end
|
71
68
|
end
|
@@ -77,40 +74,26 @@ module Capybara
|
|
77
74
|
|
78
75
|
def compare_count
|
79
76
|
# Only check filters for as many elements as necessary to determine result
|
80
|
-
if @query.options[:count]
|
81
|
-
|
82
|
-
|
83
|
-
break if @result_cache.size > count_opt
|
84
|
-
@result_cache << @results_enum.next
|
85
|
-
end
|
86
|
-
return @result_cache.size <=> count_opt
|
77
|
+
if (count = @query.options[:count])
|
78
|
+
count = Integer(count)
|
79
|
+
return load_up_to(count + 1) <=> count
|
87
80
|
end
|
88
81
|
|
89
|
-
if @query.options[:minimum]
|
90
|
-
|
91
|
-
|
92
|
-
@result_cache << @results_enum.next while @result_cache.size < min_opt
|
93
|
-
rescue StopIteration
|
94
|
-
return -1
|
95
|
-
end
|
82
|
+
if (min = @query.options[:minimum])
|
83
|
+
min = Integer(min)
|
84
|
+
return -1 if load_up_to(min) < min
|
96
85
|
end
|
97
86
|
|
98
|
-
if @query.options[:maximum]
|
99
|
-
|
100
|
-
|
101
|
-
return 1 if @result_cache.size > max_opt
|
102
|
-
@result_cache << @results_enum.next
|
103
|
-
end
|
87
|
+
if (max = @query.options[:maximum])
|
88
|
+
max = Integer(max)
|
89
|
+
return 1 if load_up_to(max + 1) > max
|
104
90
|
end
|
105
91
|
|
106
|
-
if @query.options[:between]
|
107
|
-
min, max =
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
return 0 if @query.options[:between].include? @result_cache.size
|
113
|
-
return @result_cache.size <=> min
|
92
|
+
if (between = @query.options[:between])
|
93
|
+
min, max = between.minmax
|
94
|
+
size = load_up_to(max + 1)
|
95
|
+
return 0 if between.include? size
|
96
|
+
return size <=> min
|
114
97
|
end
|
115
98
|
|
116
99
|
0
|
@@ -144,6 +127,14 @@ module Capybara
|
|
144
127
|
|
145
128
|
private
|
146
129
|
|
130
|
+
def load_up_to(num)
|
131
|
+
loop do
|
132
|
+
break if @result_cache.size >= num
|
133
|
+
@result_cache << @results_enum.next
|
134
|
+
end
|
135
|
+
@result_cache.size
|
136
|
+
end
|
137
|
+
|
147
138
|
def full_results
|
148
139
|
loop { @result_cache << @results_enum.next }
|
149
140
|
@result_cache
|