Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure Capybara to run tests in a dockerized Selenium Grid?

I have a suite of tests that I want to execute in a dockerized Selenium Grid. The tests are written in Ruby using RSpec and Capybara. Also worth noting: I'm using dinghy as a wrapper for docker-machine.

A couple weeks ago I built a proof of concept but with Nightwatch instead of RSpec+Capybara. That works fine but getting Capybara to work with the dockerized Selenium Grid has proven difficult.

I've tried numerous configurations without success. I think the closest I've gotten to a successful configuration is the following...

# docker-compose.yml

web:
  image: web:latest  # built on my machine
  environment:
    VIRTUAL_HOST: app.under.test

rspec:
  build: .
  dockerfile: Dockerfile
  environment:
    APP_HOST: app.under.test
  volumes:
    - .:/usr/src/app
  links:
    - web
    - hub

hub:
  image: selenium/hub:latest
  environment:
    VIRTUAL_HOST: selenium.hub.docker
  ports:
    - 4444:4444

node-firefox:
  image: selenium/node-firefox:latest
  environment:
    VIRTUAL_HOST: firefox.docker
  links:
    - hub

node-chrome:
  image: selenium/node-chrome:latest
  environment:
    VIRTUAL_HOST: chrome.docker
  links:
    - hub
# Dockerfile for the rspec image

FROM instructure/ruby-passenger:2.3

USER root

ENV APP_HOME /usr/src/app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

COPY Gemfile Gemfile.lock $APP_HOME/
RUN chown -R docker:docker $APP_HOME

USER docker
RUN bundle install --quiet --jobs 8
USER root

COPY . $APP_HOME
RUN chown -R docker:docker $APP_HOME

USER docker
# spec/example_test.rb:

require 'rspec'
require 'capybara'
require 'capybara/dsl'
require 'selenium-webdriver'

RSpec.configure do |config|
  config.include Capybara::DSL
end

def setup
  url = 'http://selenium.hub.docker'
  capabilities = Selenium::WebDriver::Remote::Capabilities.firefox
  Capybara.app_host = ENV['APP_HOST']

  Capybara.register_driver :remote_browser do |app|
    Capybara::Selenium::Driver.new(
      app,
      :browser => :remote,
      url: url,
      desired_capabilities: capabilities
    )
  end

  Capybara.default_driver = :remote_browser
  Capybara.javascript_driver = :remote_browser
end

describe 'This is an example' do
  it 'and it works' do
    setup
    visit '/'
    expect(page.title).to eq 'Home'
  end
end

But this ^ configuration yields the following error upon starting the tests:

1) This is an example and it works
     Failure/Error: visit '/'

 Selenium::WebDriver::Error::WebDriverError:
   unexpected response, code=200, content-type="text/html"
   <html><head><title>Selenium Grid2.0 help</title></head><body>You are using grid 2.52.0<br>Find help on the official selenium wiki : <a href='https://github.com/SeleniumHQ/selenium/wiki/Grid2' >more help here</a><br>default monitoring page : <a href='/grid/console' >console</a></body></html>
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/http/common.rb:85:in `create_response'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/http/default.rb:90:in `request'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/http/common.rb:59:in `call'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/bridge.rb:645:in `raw_execute'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/bridge.rb:123:in `create_session'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/remote/bridge.rb:87:in `initialize'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/common/driver.rb:59:in `new'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver/common/driver.rb:59:in `for'
 # /home/docker/.gem/ruby/2.3.0/gems/selenium-webdriver-2.52.0/lib/selenium/webdriver.rb:86:in `for'
 # /home/docker/.gem/ruby/2.3.0/gems/capybara-2.6.2/lib/capybara/selenium/driver.rb:13:in `browser'
 # /home/docker/.gem/ruby/2.3.0/gems/capybara-2.6.2/lib/capybara/selenium/driver.rb:45:in `visit'
 # /home/docker/.gem/ruby/2.3.0/gems/capybara-2.6.2/lib/capybara/session.rb:232:in `visit'
 # /home/docker/.gem/ruby/2.3.0/gems/capybara-2.6.2/lib/capybara/dsl.rb:51:in `block (2 levels) in <module:DSL>'
 # ./spec/example_test.rb:31:in `block (2 levels) in <top (required)>'

Any ideas? What am I missing?

Update

Got it!

def setup
  url = 'http://selenium.hub.docker/wd/hub'
  capabilities = Selenium::WebDriver::Remote::Capabilities.firefox
  Capybara.app_host = "http://#{ENV['APP_HOST']}"
  Capybara.run_server = false

  Capybara.register_driver :remote_browser do |app|
    Capybara::Selenium::Driver.new(
      app,
      :browser => :remote,
      url: url,
      desired_capabilities: capabilities
    )
  end

  Capybara.default_driver = :remote_browser
  Capybara.javascript_driver = :remote_browser
end

The key---in addition to Capybara.run_server = false and prepending http:// to the app_host---was specifying /wd/hub on the url.

Working solution here.

like image 707
mycargus Avatar asked Mar 06 '16 00:03

mycargus


People also ask

What is Capybara selenium?

Selenium. Selenium-webdriver, which is mostly used in web-based automation frameworks, is supported by Capybara. Unlike Capybara's default driver, it supports JavaScript, can access HTTP resources outside of application and can also be set up for testing in headless mode which is especially useful for CI scenarios.

What are the components that we need to start in order to build Dockerized environments for test automation?

Configuring Docker Compose yml file needs to handle: running Selenium Grid that consists of hub and Firefox and Chrome nodes. opening ports on Selenium Grid nodes for VNC access. running test execution in docker container.

What is Selenium Grid Docker?

Docker compose is the tool using which you can Selenium Grid on multiple containers. You can deploy Selenium Grid with hub and nodes for parallel execution. Docker-compose uses YAML file to configure the application services like a hub, chrome and Firefox will be the services in this case.


1 Answers

For a capybara setup there are a few things you need to worry about -

1 - where capybara connects to the browser - in most peoples cases thats locally but you're using remote and you appear to have that correctly configured

2 - where the browser attempts to connect to - the base url for that is set by Capybara.app_host - so Capybara.app_host = "http://<ip/domain name the app will be running on> - you have that set to ENV['APP_HOST'] which is set to app.under.test - I'm assuming thats an ip/domain name that resolves to an accessible interface on the machine capybara is being run on?

3 - where Capybara binds the app being tested - This is set through Capybara.server_host and Capybara.server_port - server_host defaults to 127.0.0.1 and the port is picked randomly. This is most likely where your issue lies since 127.0.0.1 on the machine running Capybara is usually not accessible from other machines You'll need to change that to be the externally available ip that matches to app.under.test from #2. You may also need to set the port if your firewall configuration requires it.

like image 50
Thomas Walpole Avatar answered Oct 06 '22 19:10

Thomas Walpole