3
votes

Question

Does headless Chrome work with self-signed certificates via the Selenium Webdriver on macOS?

Info

I am attempting to get Rails system tests driven by headless Chrome over SSL.

I have a locally self-signed certificate that I pass the the ruby Puma application server to terminate SSL requests. In order to allow drivers to ignore SSL warnings on the locally signed certificate, I am using the acceptInsecureCerts flag to configure the driver capabilities. I'm led to believe by this ticket in Chromium that this flag should be recognized as of Chrome 64+.

I can get tests to succeed with Chrome, Firefox, and headless Firefox. Tests do not pass under headless Chrome. I am using (at the time of this writing) what I believe to be the latest versions of Chrome and its variants.

Though folks in the Chromium ticket appear to be successfully running headless Chrome over locally-signed SSL with the Selenium webdriver, I have not found this to work with the setup described here. If my configuration is correct, then I am unsure if there is a limitation in headless Chrome on macOS, in Selenium webdriver ruby gem, or something else I haven't considered. If anyone has something similar working with Rails on macOS, I'd be interested to learn about your setup.

Source

Here is some code to show how I am configuring and running my RSpec/Capybara tests.

Test setup

# rails_helper.rb
# ... standard rspec rails helper setup omitted ...

Capybara.register_driver(:headless_chrome) do |app|
  options = Selenium::WebDriver::Chrome::Options.new(
    args: %w[--headless --disable-gpu --no-sandbox --disable-web-security]
  )
  capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
    acceptInsecureCerts: true,
  )
  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    options: options,
    desired_capabilities: capabilities
  )
end

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :headless_firefox
  end
end

module SystemTestHelpers
  def key_file_path
    Rails.root.join("config", "ssl", "ssl-lvh.me.key")
  end

  def cert_file_path
    Rails.root.join("config", "ssl", "ssl-lvh.me.crt")
  end

  def using_app_host(host)
    original_host = Capybara.app_host
    Capybara.app_host = host

    Capybara.server = :puma, {
      Host: "ssl://#{Capybara.server_host}?key=#{key_file_path}&cert=#{cert_file_path}"
    }
    yield
  ensure
    Capybara.app_host = original_host
  end
end

RSpec.configure do |config|
  config.include SystemTestHelpers, type: :system
end

Sample test

# spec/system/welcome_spec.rb

require 'rails_helper'

RSpec.feature "Welcome", :js, type: :system do
  scenario "Visit homepage" do
    using_app_host('https://subdomain.lvh.me') do
      visit "/"

      expect(page).to have_content('Welcome')

      expect(page).to have_content('Your domain: subdomain.lvh.me')
      expect(page).to have_content('Your protocol: https://')
    end
  end
end

Page content:

<div>
  <h2>Welcome!</h2>

  <p>Your protocol: <%= request.protocol %></p>
  <p>Your domain: <%= request.host %></p>
</div>

If I swap out the driver for headless Firefox, configured as below, the tests will pass.

Capybara.register_driver(:headless_firefox) do |app|
  options = Selenium::WebDriver::Firefox::Options.new(args: %w[--headless])

  capabilities = Selenium::WebDriver::Remote::Capabilities.firefox(
    acceptInsecureCerts: true,
  )
  Capybara::Selenium::Driver.new(
    app,
    browser: :firefox,
    options: options,
    desired_capabilities: capabilities
  )
end

The complete source code for an app that reproduces the issue, and includes the code above is located here: https://bitbucket.org/rossta/system-test-demo.

Debug output

Here's a link to some debug output from running the test in either headless Chrome or headless Firefox: https://gist.github.com/rossta/b160204baa87a520e7888c19c8b1ed98.

Note in the output that the session response does not include the 'acceptInsecureCerts' capability for Chrome (test-headless-chrome.log, line 15) while in Firefox we do see the session include the flag (test-headless-firefox.log, line 22).

System

  • MacOS 10.13.6
  • Rails 5.2.1
  • Ruby 2.4.1
  • capybara (gem) 3.5.1
  • selenium-webdriver (gem) 3.14.0
  • chromdriver-helper (gem) 2.34
  • Chrome 68.0.3440.106. Have also tried
    • Google Chrome 70.0.3524.0 canary
    • Chromium 70.0.3525.0
2
Your using_app_host method appears to be incorrect since it resets to server_host rather than app_hostThomas Walpole
Also, your demo app that shows the issue isn't publicly accessible.Thomas Walpole
@ThomasWalpole 1) Edited using_app_host 2) Thanks, updated the permissions. 3) Also, thanks for all your hard work on Capybara!rossta

2 Answers

3
votes

From your log it shows that it's starting chromedriver v2.34. acceptInsecureCerts support wasn't added until 2.35 and you should really be running the latest (2.41 currently). Update your version of chromedriver and things should work.

0
votes

caps = Selenium::WebDriver::Remote::Capabilities.firefox

caps['acceptInsecureCerts'] = true