Skip to content

Instantly share code, notes, and snippets.

@palkan
Last active April 12, 2025 15:07
Show Gist options
  • Save palkan/934f359eab62126f6445c949f17566ba to your computer and use it in GitHub Desktop.
Save palkan/934f359eab62126f6445c949f17566ba to your computer and use it in GitHub Desktop.
remote_capybara.rb

Rails System tests in Docker (Selenium version)

Running Chrome locally

You need ChromeDriver (and Chrome) installed locally and running.

You can install ChromeDriver with Homebrew on MacOS:

brew install chromedriver

Then, launch ChromeDriver as follows:

chromedriver --whitelisted-ips --allowed-origins='*' --port=9515

Finally, set REMOTE_CHROME_URL=http://host.docker.internal:9515 for your Rails container and expose test server ports (I use a dedicated service for that):

# compose.yml
services:
  # ...
  rspec_system:
    <<: *backend
    environment:
      <<: *backend_environment
      CAPYBARA_PORT: 4000
      CAPYBARA_HOST: 0.0.0.0
      REMOTE_CHROME_URL: http://host.docker.internal:9515
    ports:
      - '4000:4000'
if ENV["REMOTE_CHROME_URL"].present?
require "selenium/webdriver"
$stdout.puts "⚙️ Using remote chrome at #{ENV["REMOTE_CHROME_URL"]}"
base_options = ::Selenium::WebDriver::Chrome::Options.new.tap do
_1.add_argument("--disable-gpu")
_1.add_argument("--no-sandbox")
_1.add_argument("--disable-dev-shm-usage")
_1.add_argument("--window-size=1400,1400")
end
Capybara.register_driver(:remote_chrome) do |app|
Capybara::Selenium::Driver.new(
app,
browser: :remote,
url: ENV["REMOTE_CHROME_URL"],
capabilities: [
:chrome,
base_options
]
)
end
Capybara.register_driver(:remote_headless_chrome) do |app|
Capybara::Selenium::Driver.new(
app,
browser: :remote,
url: ENV["REMOTE_CHROME_URL"],
capabilities: [
:chrome,
base_options.dup.tap { _1.add_argument("--headless") }
]
)
end
Capybara.javascript_driver = :remote_headless_chrome
Capybara.default_driver = :remote_headless_chrome
# Overwrite settings from capybara.rb
RSpec.configure do |config|
config.before(:each, type: :system) { driven_by :remote_headless_chrome }
config.before(:each, type: :system, debug: true) { driven_by :remote_chrome }
end
Capybara.server_host = ENV.fetch("CAPYBARA_HOST", "localhost")
Capybara.server_port = ENV["CAPYBARA_PORT"].to_i if ENV["CAPYBARA_PORT"].present?
# Patch Selenium Webdriver to skip finding chromedriver locally
module Selenium
module WebDriver
class DriverFinder
def self.path(...) = nil
end
end
end
# Patch Selenium upload_file command:
# https://github.com/teamcapybara/capybara/issues/2307
# https://github.com/SeleniumHQ/selenium/blob/f4ef7be6f717fc3523a400111c9d8283d3241bb1/rb/lib/selenium/webdriver/remote/features.rb#L25
remote_commands = Selenium::WebDriver::Remote::Features::REMOTE_COMMANDS.dup
remote_commands[:upload_file] = [:post, "session/:session_id/file"]
Selenium::WebDriver::Remote::Features.send(:remove_const, :REMOTE_COMMANDS)
Selenium::WebDriver::Remote::Features.send(:const_set, :REMOTE_COMMANDS, remote_commands)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment