Search code examples
ruby-on-railsrspeccapybaraselenium-grid

Stack Level Too Deep Exception using Capybara and Selenium Grid


I am working to convert some Selenium tests to use Selenium grid and am running into a problem.

The tests run fine using a browser on the local machine.

I created a new driver like this (in spec_helper.rb):

Capybara.register_driver :selenium_remote do |app|
  caps = Selenium::WebDriver::Remote::Capabilities.chrome
  Selenium::WebDriver.for(:remote, 
    :url => 'http://gridhub:4444/grid/driver', 
    :desired_capabilities => caps)
end

When I run the tests with the new driver the hub is contacted and a node loads the Chrome driver, everything looks ok on the grid side.

The problem is that on the machine initiating the tests I am getting the following exception:

Failure/Error: Unable to find matching line from backtrace
     SystemStackError:
       stack level too deep
# /home/.rvm/gems/ruby-1.9.3-p194/gems/capybara-2.0.1/lib/capybara.rb:298

I created this bare bones test, and I am still seeing the same exception just running it:

Capybara.default_driver = :selenium_remote

describe 'I can' do
  it 'visit Google without throwing an error' do        
    visit 'http://www.google.com'
  end
end

I am using Selenium server standalone 2.26.0, Capybara 2.0.1 and RSpec 2.9.0.

Any ideas what is causing this?


Solution

  • Well, with the help of this blog post (http://www.softr.li/blog/2012/11/08/capybara-selenium-rspec-vagrant-remotely) I got it working.

    The above blog post was based on another blog post (http://www.without-brains.net/blog/2012/08/01/capybara-and-selenium-with-vagrant).

    It looks like I was registering the Capybara Selenium web driver incorrectly.

    Below is the code from the blog post that correctly registers the driver. Just using it as-is fixed my issue, then I modified it for my own use.

    The code is also in a gist (https://gist.github.com/4038197#file-capybara_remote-rb).

    Create a new Ruby file, add this code, and include it in your spec_helper.rb file.

    # SELENIUM_SERVER is the IP address or hostname of the system running Selenium
    # Server, this is used to determine where to connect to when using one of the
    # selenium_remote_* drivers
    SELENIUM_SERVER = "10.10.11.1"
    
    # SELENIUM_APP_HOST is the IP address or hostname of this system (where the
    # tests run against) as reachable for the SELENIUM_SERVER. This is used to set
    # the Capybara.app_host when using one of the selenium_remote_* drivers
    SELENIUM_APP_HOST = "10.10.11.2"
    
    # CAPYBARA_DRIVER is the Capybara driver to use, this defaults to Selenium with
    # Firefox
    CAPYBARA_DRIVER = "selenium_remote_firefox"
    
    # At this point, Capybara.default_driver is :rack_test, and
    # Capybara.javascript_driver is :selenium. We can't run :selenium in the Vagrant box,
    # so we set the javascript driver to :selenium_remote_firefox which we're going to
    # configure.
    Capybara.javascript_driver = :selenium_remote_firefox
    
    RSpec.configure do |config|
    
      config.before(:each) do
        if selenium_remote?
          Capybara.app_host = "http://#{SELENIUM_APP_HOST}:#{page.driver.rack_server.port}"
        end
      end
    
      config.after(:each) do
        Capybara.reset_sessions!
        Capybara.use_default_driver
        Capybara.app_host = nil
      end
    
      # Determines if a selenium_remote_* driver is being used
      def selenium_remote?
        !(Capybara.current_driver.to_s =~ /\Aselenium_remote/).nil?
      end
    end
    
    # CapybaraDriverRegistrar is a helper class that enables you to easily register
    # Capybara drivers
    class CapybaraDriverRegistrar
    
      # register a Selenium driver for the given browser to run on the localhost
      def self.register_selenium_local_driver(browser)
        Capybara.register_driver "selenium_#{browser}".to_sym do |app|
          Capybara::Selenium::Driver.new(app, browser: browser)
        end
      end
    
      # register a Selenium driver for the given browser to run with a Selenium
      # Server on another host
      def self.register_selenium_remote_driver(browser)
        Capybara.register_driver "selenium_remote_#{browser}".to_sym do |app|
          Capybara::Selenium::Driver.new(app, browser: :remote, url: "http://#{SELENIUM_SERVER}:4444/wd/hub", desired_capabilities: browser)
        end
      end
    end
    
    # Register various Selenium drivers
    CapybaraDriverRegistrar.register_selenium_remote_driver(:firefox)
    

    Now any RSpec example with the :js => true metadata will use this driver.