LoginSignup
18

More than 3 years have passed since last update.

Docker環境でRspec×Capybara×ChromeDriverを動作させる

Last updated at Posted at 2021-01-26

作成した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

元々はdbwebwebpackerのみの構成としていましたが、新たにテスト用のDBのtest-dbと、CapybaraでのChrome実行用のchromeを追加しました。
webにChromeをインストールする手もありますが、コンテナに複数の機能をもたせるのはDockerの設計思想に合っていないと思い、この構成としました。

docker-compose.yml
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

現状の設定内容では、分ける必要がないかもしれませんが、念のため分けて定義しています。

.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を読み込んでいます。

spec/rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

capybara.rbは以下のような記載にしています。

spec/support/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-railscapybara等、必要なgemは導入済みです。
今回のDocker環境でのRspecにあたり以下の記述を修正しました。

Gemfile

  group :test do
-   gem 'webdrivers'
+   gem 'webdrivers', require: !ENV['SELENIUM_DRIVER_URL']
  end

このrequireの記載がないと、capybara.rbdriven_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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18