作成したrailsアプリをDocker環境にのせ、開発環境上で問題なく動作するよう設定しました。
しかし、この状態のままではRspecが正しく動作しなくなっていたため、内容を見直しました。
RspecやCapybaraを元々利用していた前提であり、それらの導入については記載しておりません。
また、前回書いたDocker導入記事の続きの記事となります。Dockerについての設定内容はこちらをご参照ください。
ローカルRails6アプリのDocker環境への移行(ついでにMysql導入) - Qiita
##環境
- ruby 2.7.2
- Rails 6.0.3
- Mysql 8.0.22
- rspec-rails 4.0.2
- capybara 3.34.0
- selenium-webdriver 3.142.7
##docker-compose.yml
元々はdb
とweb
とwebpacker
のみの構成としていましたが、新たにテスト用のDBのtest-db
と、CapybaraでのChrome実行用のchrome
を追加しました。
web
にChromeをインストールする手もありますが、コンテナに複数の機能をもたせるのはDockerの設計思想に合っていないと思い、この構成としました。
version: '3'
services:
db:
image: mysql:8.0.22
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
ports:
- '3306:3306'
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_DATABASE: ${DEV_DATABASE}
MYSQL_ROOT_PASSWORD: ${DEV_ROOTPASS}
MYSQL_USER: ${DEV_USERNAME}
MYSQL_PASSWORD: ${DEV_USERPASS}
### 追加ここから ###
test-db: #Rspecでのテスト実行用のコンテナ
image: mysql:8.0.22
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
ports:
- '4306:3306' #開発用とはポート番号を別にする
environment: #接続情報は開発のものと一応分けます
MYSQL_DATABASE: ${TEST_DATABASE}
MYSQL_ROOT_PASSWORD: ${TEST_ROOTPASS}
MYSQL_USER: ${TEST_USERNAME}
MYSQL_PASSWORD: ${TEST_USERPASS}
### 追加ここまで ###
web: &app_base
build:
context: .
dockerfile: ./docker/rails/Dockerfile
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b 0.0.0.0"
depends_on:
- db
- chrome #追加
ports:
- "3000:3000"
volumes:
- .:/app
- gem_modules:/vendor/bundle
- node_modules:/node_modules
tty: true
stdin_open: true
environment:
WEBPACKER_DEV_SERVER_HOST: webpacker
BUNDLE_APP_CONFIG: ./.bundle
SELENIUM_DRIVER_URL: http://chrome:4444/wd/hub #追加、どのコンテナのブラウザを使用するか指定
webpacker:
<<: *app_base
command: bash -c "bundle exec bin/webpack-dev-server"
depends_on:
- web
ports:
- '3035:3035'
tty: false
stdin_open: false
environment:
BUNDLE_APP_CONFIG: ./.bundle
NODE_ENV: development
RAILS_ENV: development
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
### 追加ここから ###
chrome: #Chromeでのテスト実行用コンテナ
image: selenium/standalone-chrome #Chromeがインストールされたイメージ
ports:
- '4444:4444'
### 追加ここまで ###
volumes:
db_data:
gem_modules:
node_modules:
##database.yml
test-db
に合わせ設定しました。
:config/database.yml
default: &default
adapter: mysql2
username: app
password: password
host: db #サービス名を指定
development:
<<: *default
database: mysql_development
+test
+ <<: *default
+ database: mysql_test
+ host: test-db
##.env
現状の設定内容では、分ける必要がないかもしれませんが、念のため分けて定義しています。
DEV_DATABASE=mysql_development
DEV_USERNAME=app
DEV_USERPASS=password
DEV_ROOTPASS=password
+TEST_DATABASE=mysql_test
+TEST_USERNAME=app
+TEST_USERPASS=password
+TEST_ROOTPASS=password
##capybara.rb
.rsepc
に--require rails_helper
と記載することで、spec/rails_helper
を読み込んでいます。
その中の以下の行を有効にすることで、spec/support/capybara.rb
を読み込んでいます。
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
capybara.rb
は以下のような記載にしています。
Capybara.register_driver :remote_chrome do |app|
url = ENV['SELENIUM_DRIVER_URL']
caps = ::Selenium::WebDriver::Remote::Capabilities.chrome(
'goog:chromeOptions' => {
'args' => [
'no-sandbox',
'headless',
'disable-gpu',
'window-size=1680,1050'
]
}
)
Capybara::Selenium::Driver.new(app, browser: :remote, url: url, desired_capabilities: caps)
end
RSpec.configure do |config|
config.before(:each, type: :system) do
driven_by :rack_test
end
config.before(:each, type: :system, js: true) do
#driven_by :selenium_chrome_headless
Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
Capybara.app_host = "http://#{Capybara.server_host}"
driven_by :remote_chrome
end
end
元々javascriptをテストできるよう、driven_by :selenium_chrome_headless
としておりました。
今回は:remote_chrome
というドライバーを設定し、browser: :remote
とすることで、web
コンテナのブラウザを使用するのではなくchrome
コンテナのブラウザを使用するように設定しています。
(そもそもweb
コンテナにはブラウザが入っていないので、このままだとエラーとなってしまいます。)
##Gemfile
元々ローカル環境でrspecを導入していたため、rspec-rails
やcapybara
等、必要なgemは導入済みです。
今回のDocker環境でのRspecにあたり以下の記述を修正しました。
group :test do
- gem 'webdrivers'
+ gem 'webdrivers', require: !ENV['SELENIUM_DRIVER_URL']
end
このrequire
の記載がないと、capybara.rb
のdriven_by :remote_chrome
で以下のようなエラーが発生してしまうので付与しています。
Webdrivers::BrowserNotFound: Failed to find Chrome binary.
おそらくホストのブラウザを探しにいくことによるエラーだと思われます。
参考:Failed to find Chrome binary with Rails 6 rc2 · Issue #148 · titusfortner/webdrivers
##おわりに
以下のコマンドを実行することにより、問題なく動作することを確認できました。
docker-compose up -d
docker-compose exec web bin/rspec
chrome
コンテナのブラウザを使用するところで苦戦しましたが、無事に動作するようになりよかったです。
次はこの環境をCircleCIで自動テストできるようにしたいと思います。
##参考記事
・willnet/capybara-readme-ja: Capybara の README 和訳
・Rails on Docker(alpine)でdocker-seleniumを使わないでSelenium+RSpec+Capybaraでテスト自動化してみる - Qiita
・Rails + Selenium + DockerでSystemSpecの環境構築 - Qiita
・初めてDocker + RailsでE2EテストしようとしてWebdrivers::BrowserNotFound: Failed to find Chrome binary. エラーにはまった時の話 - Qiita