Reputation: 2497
I'm having issues with my specs not timing out. Some of my specs are getting to a certain point and just hanging. I'm sure there is something wrong with one of the spec resulting in it being broken, what I can't figure out is why they are just hanging indefinitely when I have a timeout defined...
# frozen-string-literal: true
require 'rspec'
require 'capybara/rspec'
require 'capybara/dsl'
require 'selenium-webdriver'
require 'site_prism'
Dir[File.dirname(__FILE__) + '/page_objects/*/*.rb'].each do |page_object|
require page_object
end
def wait_for_ajax
Timeout.timeout(Capybara.default_max_wait_time) do
loop until page.evaluate_script('jQuery.active').zero? && page.has_no_css?(".k-loading-color")
end
end
def whole_page
Capybara.current_session
end
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.default_driver = :selenium
Capybara.app_host = #REDACTED
Capybara.default_max_wait_time = 20
RSpec.configure do |config|
config.before(:each) do
config.include Capybara::DSL
end
config.after(:each) do
Capybara.reset_sessions!
end
end
Upvotes: 1
Views: 286
Reputation: 49870
You don't mention what commands it's hanging on, but I'm going to guess it's in your wait_for_ajax
method. If that's the case it's because you're using Timeout.timeout
which is the most dangerous to use method Ruby provides. The way it works is by starting a second thread which will then raise an exception in the original thread when the timeout occurs. The problem with that is the exception can occur anywhere in the original thread which means if the block inside the timeout
call is doing anything non-trivial it can end up in a completely unrecoverable state (network comms, etc). Basically Timeout.timeout
can only ever be safely used with a VERY detailed knowledge of every little thing occurring it its block, which means it effectively should never be used around any calls to a third party library. Instead you should just use a timer and sleep if you need timeout. Something like
def wait_for_ajax
start = Time.now
until page.evaluate_script('jQuery.active').zero? && page.has_no_css?(".k-loading-color", wait: false) do
sleep 0.1
raise <Some Error> if (Time.now - start) > Capybara.default_max_wait_time
end
end
That being said you really shouldn't need wait_for_ajax
with a useable UI and properly written tests.
Additionally, by including capybara/rspec
you've already set up for reset_sessions
to be called after every test and for Capybara::DSL
to be included into the types of tests it should be included into - https://github.com/teamcapybara/capybara/blob/master/lib/capybara/rspec.rb#L9 - so by adding your own after
block you're just ending up calling reset_sessions
twice after every test which is just a waste of time.
Upvotes: 3