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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With