はじめに
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.0
2.ブラウザで 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 .