title: "Refused to connect" using ChromeDriver, Capybara & Docker Compose
body: <p>I'm trying to make the move from PhantomJS to Headless Chrome and have run into a bit of a snag. For local testing, I'm using Docker Compose to get all dependent services up and running. To provision Google Chrome, I'm using an image that bundles both it and ChromeDriver together while serving it on port <code>4444</code>. I then link it to the my app container as follows in this simplified <code>docker-compose.yml</code> file:</p>
  
  <pre><code>web:
      image: web/chrome-headless
      command: [js-specs]
      stdin_open: true
      tty: true
      environment:
          - RACK_ENV=test
          - RAILS_ENV=test
      links:
          - "chromedriver:chromedriver"
  
  chromedriver:
      image: robcherry/docker-chromedriver:latest
      ports: 
          - "4444"
      cap_add: 
          - SYS_ADMIN
      environment:
          CHROMEDRIVER_WHITELISTED_IPS: ""
  </code></pre>
  
  <p>Then, I have a <code>spec/spec_helper.rb</code> file that bootstraps the testing environment and associated tooling. I define the <code>:headless_chrome</code> driver and point it to ChromeDriver's local binding; <code>http://chromedriver:4444</code>. I'm pretty sure the following is correct:</p>
  
  <pre><code>Capybara.javascript_driver = :headless_chrome
  
  Capybara.register_driver :chrome do |app|
      Capybara::Selenium::Driver.new(app, browser: :chrome)
  end
  
  Capybara.register_driver :headless_chrome do |app|
      capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
      chromeOptions: { args: %w[headless disable-gpu window-size=1440,900] },
  )
  
  Capybara::Selenium::Driver.new app,
      browser: :chrome,
      url: "http://chromedriver:4444/",
      desired_capabilities: capabilities
  end
  </code></pre>
  
  <p>We also use VCR, but I've configured it to ignore any connections to the port used by ChromeDriver:</p>
  
  <pre><code>VCR.configure do |c|
      c.cassette_library_dir = 'spec/vcr_cassettes'
      c.default_cassette_options = { record: :new_episodes }
      c.ignore_localhost = true
      c.allow_http_connections_when_no_cassette = false
      c.configure_rspec_metadata!
      c.ignore_hosts 'codeclimate.com'
      c.hook_into :webmock, :excon
  
      c.ignore_request do |request|
          URI(request.uri).port == 4444
      end
  end
  </code></pre>
  
  <p>I start the services with Docker Compose, which triggers the test runner. The command is pretty much this:</p>
  
  <pre><code>$ bundle exec rspec --format progress --profile --tag 'broken' --tag 'js' --tag '~quarantined'
  </code></pre>
  
  <p>After a bit of waiting, I encounter the first failed test:</p>
  
  <pre><code>  1) Beta parents code redemption:  redeeming a code on the dashboard when the parent has reached the code redemption limit does not display an error message for cart codes
       Failure/Error: fill_in "code", with: "BOOK-CODE"
  
       Capybara::ElementNotFound:
         Unable to find field "code"
       # ./spec/features/beta_parents_code_redemption_spec.rb:104:in `block (4 levels) in &lt;top (required)&gt;'
  </code></pre>
  
  <p>All specs have the same error. So, I shell into the container to run the tests myself manually and capture the HTML it's testing against. I save it locally and open it up in my browser to be welcomed by the following Chrome error page. It would seem ChromeDriver isn't evaluating the spec's HTML because it can't reach it, so it attempts to run the tests against this error page.</p>
  
  <p>Given the above information, what am I doing wrong here? I appreciate any and all help as moving away from PhantomJS would solve <em>so</em> many headaches for us. </p>
  
  <p>Thank you so much in advance. Please, let me know if you need extra information.</p>
  
  <p><a href="https://i.stack.imgur.com/6mEGL.png" rel="noreferrer"><img src="https://i.stack.imgur.com/6mEGL.png" alt="enter image description here"></a></p>