Capybara / Selenium gets Net :: ReadTimeout randomly at location.reload ()
I am using Capybara, a selenium-webdriver gem and chromedriver, to run my javascript validated tests.
The problem is that about 50% of our builds fail due to an error Net::ReadTimeout
. At first it showed up as an "could not find element" error, but after I increased the Capybara max to 30 seconds, I started seeing a timeout.
I looked at the screenshots when the timeout occurs, it is stuck in the "Successfully registered" modal, which we will show briefly before using the Javascript function location.reload()
to reload the page.
I ran the test locally and sometimes reproduce it randomly as well. Sometimes it snaps onto this modal and reloads so quickly that you can barely see it, while other times it just hangs forever.
I don't like the issue of compiling assets as the site is already loaded at this point for the user to be able to access the login form.
I wonder if anyone has seen this before and knows the solution.
Specific code:
visit login_path
page.within '#sign-in-pane__body' do
fill_in 'Email', with: user.email
click_button 'Submit'
end
expect(page).to have_content 'Enter Password'
page.within '#sign-in-pane__body' do
fill_in 'Password', with: user.password
click_button 'Submit'
end
expect(page).to have_text 'Home page landing text'
The gap happens between click_button 'Submit'
and waiting for the home page text.
The logic thread causing the timeout is a custom form, we expect the server to render a template .js.erb
that fires a JS event on successful login. When this trigger occurs, we show a modal statement that the login was successful, then execute location.reload()
.
source to share
It turned out that this is not an exception to execute location.reload()
in JS. Sometimes it's just a visit to a page.
The solution for me was to create an HTTP client for the selenium driver and define a longer timeout:
Capybara.register_driver :chrome do |app|
client = Selenium::WebDriver::Remote::Http::Default.new
client.read_timeout = 120
Capybara::Selenium::Driver.new(app, {browser: :chrome, http_client: client})
end
source to share
Solved a similar issue using my own version of the visit method:
def safe_visit(url)
max_retries = 3
times_retried = 0
begin
visit url
rescue Net::ReadTimeout => error
if times_retried < max_retries
times_retried += 1
puts "Failed to visit #{current_url}, retry #{times_retried}/#{max_retries}"
retry
else
puts error.message
puts error.backtrace.inspect
exit(1)
end
end
end
source to share