Fixing Selenium Timeout::Error
While running our cucumber test suite, sometimes Firefox would hang and raise a Timeout::Error with this backtrace:
When I go to the home page
execution expired (Timeout::Error)
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/timeout.rb:64:in `rbuf_fill'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/protocol.rb:116:in `readuntil'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/protocol.rb:126:in `readline'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:2028:in `read_status_line'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:2017:in `read_new'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:1051:in `request'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:1037:in `request'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:543:in `start'
/Users/brian/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/net/http.rb:1035:in `request'
./features/step_definitions/web_steps.rb:24:in `/^(?:|I )go to (.+)$/'Sometimes the tests would fail simply when going to a page, as above. Other times they would fail on a large file upload. Curiously, we’d get only get this timeout error while running the full test suite.
The Timeout::Error was especially frustrating because it would then appear after every scenario. It continued to be raised when Capybara tries to reset each of its sessions.
We still haven’t gotten to the root of the problem. Clearly, Firefox has hung or the connection between it and the webdriver server have been lost. In the mean time, we’ve worked out some stopgaps.
If it appears that selenium-webdriver isn’t giving Firefox enough time to complete the request, you can set the timeout duration by adding the following code to features/env.rb:
Capybara.register_driver :selenium do |app| http_client = Selenium::WebDriver::Remote::Http::Default.new http_client.timeout = 100 Capybara::Selenium::Driver.new(app, :browser => :firefox, :http_client => http_client) end
If more time doesn’t prevent the problem, you can at least prevent the Timeout::Error from breaking all the other tests. Add the following to features/env.rb:
After("@selenium") do |scenario| if scenario.exception.is_a? Timeout::Error # restart Selenium driver Capybara.send(:session_pool).delete_if { |key, value| key =~ /selenium/i } end end
If any Selenium scenarios raises a Timeout::Error, the above code will cause Capybara to forget about the Selenium session and won’t try to reset it at the end of every test. If Cucumber runs across another Selenium test, Capybara will fire up a new browser.
Let us know if you discover a solution to the problem.
-
Justin — October 10, 2011
I run into this all the time! Please let me know if you find the cause…
