Optionally allow `all` results to be reloaded when stale
This commit is contained in:
parent
0783f95d54
commit
288c8dfe7a
|
@ -9,6 +9,8 @@ Release date: unreleased
|
|||
any breaking changes, but due to the nature of the 2.7 changes and some selector types accepting
|
||||
Hashes as locators there are a lot of edge cases. If you find any broken cases please report
|
||||
them and I'll see if they're fixable.
|
||||
* Optionally allow `all` results to be reloaded when stable - Beta feature - may be removed in
|
||||
future version
|
||||
|
||||
# Version 3.30.0
|
||||
Release date: 2019-12-24
|
||||
|
|
|
@ -27,9 +27,11 @@ module Capybara
|
|||
@query_scope = query_scope
|
||||
@query = query
|
||||
@allow_reload = false
|
||||
@query_idx = nil
|
||||
end
|
||||
|
||||
def allow_reload!
|
||||
def allow_reload!(idx = nil)
|
||||
@query_idx = idx
|
||||
@allow_reload = true
|
||||
end
|
||||
|
||||
|
@ -545,14 +547,13 @@ module Capybara
|
|||
|
||||
# @api private
|
||||
def reload
|
||||
if @allow_reload
|
||||
begin
|
||||
reloaded = @query.resolve_for(query_scope.reload)&.first
|
||||
return self unless @allow_reload
|
||||
|
||||
@base = reloaded.base if reloaded
|
||||
rescue StandardError => e
|
||||
raise e unless catch_error?(e)
|
||||
end
|
||||
begin
|
||||
reloaded = @query.resolve_for(query_scope.reload)[@query_idx.to_i]
|
||||
@base = reloaded.base if reloaded
|
||||
rescue StandardError => e
|
||||
raise e unless catch_error?(e)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
|
|
@ -235,13 +235,16 @@ module Capybara
|
|||
# @option options [Integer] maximum Maximum number of matches that are expected to be found
|
||||
# @option options [Integer] minimum Minimum number of matches that are expected to be found
|
||||
# @option options [Range] between Number of matches found must be within the given range
|
||||
# @option options [Boolean] allow_reload Beta feature - May be removed in any version.
|
||||
# When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
|
||||
# if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
|
||||
# @overload all([kind = Capybara.default_selector], locator = nil, **options)
|
||||
# @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
|
||||
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
|
||||
# @yieldreturn [Boolean] Should the element be considered in the results?
|
||||
# @return [Capybara::Result] A collection of found elements
|
||||
# @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
|
||||
def all(*args, **options, &optional_filter_block)
|
||||
def all(*args, allow_reload: false, **options, &optional_filter_block)
|
||||
minimum_specified = options_include_minimum?(options)
|
||||
options = { minimum: 1 }.merge(options) unless minimum_specified
|
||||
options[:session_options] = session_options
|
||||
|
@ -250,6 +253,7 @@ module Capybara
|
|||
begin
|
||||
synchronize(query.wait) do
|
||||
result = query.resolve_for(self)
|
||||
result.allow_reload! if allow_reload
|
||||
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
||||
|
||||
result
|
||||
|
|
|
@ -152,7 +152,7 @@ module Capybara
|
|||
yield # simple nodes don't need to wait
|
||||
end
|
||||
|
||||
def allow_reload!
|
||||
def allow_reload!(*)
|
||||
# no op
|
||||
end
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ module Capybara
|
|||
@filter_errors = []
|
||||
@results_enum = lazy_select_elements { |node| query.matches_filters?(node, @filter_errors) }
|
||||
@query = query
|
||||
@allow_reload = false
|
||||
end
|
||||
|
||||
def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
|
||||
|
@ -43,7 +44,7 @@ module Capybara
|
|||
@result_cache.each(&block)
|
||||
loop do
|
||||
next_result = @results_enum.next
|
||||
@result_cache << next_result
|
||||
add_to_cache(next_result)
|
||||
yield next_result
|
||||
end
|
||||
self
|
||||
|
@ -130,13 +131,26 @@ module Capybara
|
|||
@elements.length
|
||||
end
|
||||
|
||||
##
|
||||
# @api private
|
||||
#
|
||||
def allow_reload!
|
||||
@allow_reload = true
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_to_cache(elem)
|
||||
elem.allow_reload!(@result_cache.size) if @allow_reload
|
||||
@result_cache << elem
|
||||
end
|
||||
|
||||
def load_up_to(num)
|
||||
loop do
|
||||
break if @result_cache.size >= num
|
||||
|
||||
@result_cache << @results_enum.next
|
||||
add_to_cache(@results_enum.next)
|
||||
end
|
||||
@result_cache.size
|
||||
end
|
||||
|
|
|
@ -47,6 +47,39 @@ Capybara::SpecHelper.spec '#all' do
|
|||
expect { @session.all('//p', schmoo: 'foo') }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'should not reload by default', requires: [:driver] do
|
||||
paras = @session.all(:css, 'p', minimum: 3)
|
||||
expect { paras[0].text }.not_to raise_error
|
||||
@session.refresh
|
||||
expect { paras[0].text }.to raise_error do |err|
|
||||
expect(err).to be_an_invalid_element_error(@session)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with allow_reload' do
|
||||
it 'should reload if true' do
|
||||
paras = @session.all(:css, 'p', allow_reload: true, minimum: 3)
|
||||
expect { paras[0].text }.not_to raise_error
|
||||
@session.refresh
|
||||
sleep 1 # Ensure page has started to reload
|
||||
expect(paras[0]).to have_text('Lorem ipsum dolor')
|
||||
expect(paras[1]).to have_text('Duis aute irure dolor')
|
||||
end
|
||||
|
||||
it 'should not reload if false', requires: [:driver] do
|
||||
paras = @session.all(:css, 'p', allow_reload: false, minimum: 3)
|
||||
expect { paras[0].text }.not_to raise_error
|
||||
@session.refresh
|
||||
sleep 1 # Ensure page has started to reload
|
||||
expect { paras[0].text }.to raise_error do |err|
|
||||
expect(err).to be_an_invalid_element_error(@session)
|
||||
end
|
||||
expect { paras[2].text }.to raise_error do |err|
|
||||
expect(err).to be_an_invalid_element_error(@session)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with css selectors' do
|
||||
it 'should find all elements using the given selector' do
|
||||
expect(@session.all(:css, 'h1').first.text).to eq('This is a test')
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<option>Miss</option>
|
||||
<option disabled="disabled">Other</option>
|
||||
</select>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="customer_name">Customer Name
|
||||
|
|
Loading…
Reference in New Issue