Enable rack_test driver to reload nodes if stale

This commit is contained in:
Thomas Walpole 2019-02-15 12:58:45 -08:00
parent 8930306e2f
commit 3d9c6997b0
7 changed files with 71 additions and 10 deletions

View File

@ -83,11 +83,18 @@ module Capybara
yield
rescue StandardError => err
session.raise_server_error!
raise err unless driver.wait? && catch_error?(err, errors)
raise err if timer.expired?
raise err unless catch_error?(err, errors)
sleep(0.01)
reload if session_options.automatic_reload
if driver.wait?
raise err if timer.expired?
sleep(0.01)
reload if session_options.automatic_reload
else
old_base = @base
reload if session_options.automatic_reload
raise err if old_base == @base
end
retry
ensure
session.synchronized = false

View File

@ -102,4 +102,8 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
def put(*args, &block); browser.put(*args, &block); end
def delete(*args, &block); browser.delete(*args, &block); end
def header(key, value); browser.header(key, value); end
def invalid_element_errors
[ Capybara::RackTest::Errors::StaleElementReferenceError ]
end
end

View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
module Capybara::RackTest::Errors
class StaleElementReferenceError < StandardError
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'capybara/rack_test/errors'
class Capybara::RackTest::Node < Capybara::Driver::Node
BLOCK_ELEMENTS = %w[p h1 h2 h3 h4 h5 h6 ol ul pre address blockquote dl div fieldset form hr noscript table].freeze
@ -106,18 +108,27 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
native.path
end
def find_xpath(locator)
def find_xpath(locator, **_hints)
native.xpath(locator).map { |el| self.class.new(driver, el) }
end
def find_css(locator)
def find_css(locator, **_hints)
native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |el| self.class.new(driver, el) }
end
self.public_instance_methods(false).each do |meth_name|
alias_method "unchecked_#{meth_name}", meth_name
private "unchecked_#{meth_name}"
define_method meth_name do |*args|
stale_check
send("unchecked_#{meth_name}", *args)
end
end
def ==(other)
native == other.native
end
protected
# @api private
@ -141,6 +152,10 @@ protected
private
def stale_check
raise Capybara::RackTest::Errors::StaleElementReferenceError unless native.document == driver.dom
end
def deselect_options
select_node.find_xpath('.//option[@selected]').each { |node| node.native.remove_attribute('selected') }
end

View File

@ -77,9 +77,9 @@ module Capybara
def is_displayed_atom # rubocop:disable Naming/PredicateName
@@is_displayed_atom ||= begin
browser.send(:bridge).send(:read_atom, 'isDisplayed')
rescue StandardError
# If the atom doesn't exist or other error
""
rescue StandardError
# If the atom doesn't exist or other error
''
end
end
end

View File

@ -26,6 +26,29 @@ Capybara::SpecHelper.spec '#within' do
end
expect(@session).to have_content('Bar')
end
it 'should reload the node if the page is changed' do
@session.within(:css, '#for_foo') do
@session.visit('/with_scope_other')
expect(@session).to have_content('Different text')
end
end
it 'should reload multiple nodes if the page is changed' do
@session.within(:css, '#for_bar') do
@session.within(:css, 'form[action="/redirect"]') do
@session.refresh
expect(@session).to have_content('First Name')
end
end
end
it 'should error if the page is changed and a matching node no longer exists' do
@session.within(:css, '#for_foo') do
@session.visit('/')
expect { @session.text }.to raise_error(StandardError)
end
end
end
context 'with XPath selector' do

View File

@ -0,0 +1,6 @@
<h1>This page is used for testing various scopes</h1>
<p id="for_foo">
Different text same wrapper id
</p>