はじめに
Selenium の実行時に、開発メンバーの PC 環境に依存して結果が変わってしまうことがありました。
そこで、Docker を利用して同一の環境でテストを実行できるようにしました。
PCに依存する原因:
- 開発環境のスペックの違い
 - Chrome のバージョン差異 など
 
回避したかったこと
- 「レビュー時にテストを実行するとエラーになる……。え、そっちでは失敗しないの?」
 - 「修正箇所とは関係ないところでエラーになるんだけど……。」
 
メリット
- 同じバージョンのChromeDriverで実行できるため、環境差異が発生しない
 - PC リソース使用を限定できる(CPU/メモリ割り当て可能)
 
前提
- Rails アプリ側はすでに Selenium が実行できる環境であること
 - 今回は既存の処理を修正し、Rails アプリはホスト PC 上で動作(
http://localhost:3000)、Docker 化はしていない - 開発環境は MacBook Pro 2021 (Apple M1 Pro)
 
目次
環境情報
Seleniumコンテナ: selenium/standalone-chromium:138.0
Chromeバージョン: 138.0
Selenium Grid: <http://localhost:4444>
VNC: <http://localhost:7900>
Railsアプリケーション: <http://localhost:3000>
Railsテストアプリケーション: <http://localhost:3001>
使用したDocker
selenium/standalone-chromium(公式イメージ)を利用しました。linux/amd64 と linux/arm64 の両方に対応しています。
構築手順
1.Seleniumコンテナの起動
# バージョン指定(138.0)でSeleniumコンテナを起動
docker run -d 
  --name selenium-chrome 
  -p 4444:4444 
  -p 7900:7900 
  --shm-size="2g" 
  --add-host=host.docker.internal:host-gateway 
 -v "$(pwd)/tmp/data/downloads:/tmp/downloads" 
  selenium/standalone-chromium:138.0
  
  # ダウンロード対応のため、ボリュームマウントの追加
  ホスト: /tmp/data/downloads
  docker: /tmp/downloads
2.Railsアプリケーションの設定
config/environments/test.rb
# これを追加しないとアクセスエラーになります
config.hosts << "host.docker.internal" "host.docker.internal" はDockerからホスト上のサービスにアクセスするために必要です。
今回のケースでは、RSpec 実行時にホスト側で起動している Rails アプリにアクセスするために指定しました。
この設定がないと以下のようなエラーが発生します。
[ActionDispatch::HostAuthorization::DefaultResponseApp] Blocked host: host.docker.internal
3.Selenium設定の修正
spec/support/capybara.rb
RSpec.configure do |config|
  config.before(:each, type: :system, selenium: true) do
    # 環境変数SELENIUM_DOCKERがtrueの場合、Docker環境で実行する
    if ENV['SELENIUM_DOCKER']
      driven_by(:selenium_remote_chrome)
    else
      driven_by(:selenium_chrome)
    end
  end
end
spec/spec_helper.rb
# Docker環境用のSeleniumドライバー
Capybara.register_driver :selenium_remote_chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--no-sandbox')
  options.add_argument('--headless')
  options.add_argument('--disable-dev-shm-usage')
  options.add_argument('--disable-gpu')
  options.add_argument('--window-size=1920,1080')
  Capybara::Selenium::Driver.new(
    app,
    browser: :remote,
    url: '<http://localhost:4444/wd/hub>',
    options: options
  )
end
# Capybara設定
Capybara.configure do |config|
  # test環境用の専用ポートを指定する3001固定
  config.server_port = 3001
  # Docker環境用のapp_host設定
  config.app_host = 'http://host.docker.internal:3001' if ENV['SELENIUM_DOCKER']
end
4.テスト実行
# 全テスト実行
SELENIUM_DOCKER=true bundle exec rspec spec/system/hogehoge_spec.rb --tag selenium
Seleniumが動作しているところが見たい
1.VNCのパスワード無効にして、docker起動
docker run -d --name selenium-chrome -p 4444:4444 -p 7900:7900 --shm-size="2g" --add-host=host.docker.internal:host-gateway -e SE_VNC_NO_PASSWORD=1 selenium/standalone-chromium:138.02.ブラウザで http://localhost:7900 を開く
3.「Connect」をクリック
4. headlessモードを無効
spec/spec_helper.rb
# Docker環境用のSeleniumドライバー
Capybara.register_driver :selenium_remote_chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--no-sandbox')
#  options.add_argument('--headless') ←コメントアウト5.テスト実行
残課題
- ファイル選択周り
 
おまけコマンド
# 既存のコンテナを停止・削除
docker stop selenium-chrome && docker rm selenium-chrome
# コンテナの状態確認
docker ps
# コンテナの停止・削除
docker stop selenium-chrome && docker rm selenium-chrome
# コンテナのログ確認
docker logs selenium-chrome
# イメージの確認
docker images selenium/standalone-chromium
# コンテナログ確認
docker logs selenium-chrome
# Railsアプリケーション確認
curl -I <http://localhost:3000>
# Selenium Grid状態確認
curl -s <http://localhost:4444/status> | jq .
