🧸

Docker環境にCapybaraを導入する

2022/08/02に公開
1

Docker環境で開発してるRailsアプリケーションに対して、E2EテスティングフレームワークであるCapybaraを導入する際にところどころハマったので手順を書き残す。

全体像

webコンテナ上でテストを実行する。chromeコンテナではブラウザが動作している。
後述するCapybaraの設定のほとんどは、Capybaraとchromeコンテナを適切に通信させるためのもの。

手順

1. 必要なgemをインストール

Gemfileに以下のように記述し、capybaraとselenium-webdriverをダウンロードする。

group :test do
  ...
  gem 'capybara'
  gem 'selenium-webdriver'
end

2. docker-compose.ymlを編集

Seleniumで操作可能なブラウザが動作するコンテナが必要なので、そのための設定をdocker-compose.ymlに追記する。

services:
  ...
  chrome:
    image: seleniarm/standalone-chromium
    ports:
      - "4444:4444"
    # ref: https://github.com/seleniumhq-community/docker-seleniarm#--shm-size2g
    shm_size: 2gb

私はM1 macユーザーなので、Seleniumが配布しているイメージの中でも、seleniarm/standalone-chromiumを用いた。ARMでない方はselenium/standalone-chromeなど、環境に合わせて選んでください。

ちなみに、4444ポートをバインドすることで、http://localhost:4444でSeleniumのダッシュボードをみることができるようになる。

3. Capybaraの設定

spec/rails_helper.rbに以下のような設定を記述する。

# Capybaraに、remote_chromeという名前のdriverを登録する
Capybara.register_driver :remote_chrome do |app|
  options = {
    browser: :remote,
    # remote browserが動作しているurlを指定
    # 今回は`chrome`という名前で`docker-compose.yml`に登録したのでhost名は`chrome`
    url: 'http://chrome:4444/wd/hub',
    capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
      # 各設定はここを参照: https://peter.sh/experiments/chromium-command-line-switches/
      'goog:chromeOptions': {
        args: %w[
          headless
          disable-gpu
          window-size=1400,2000
          no-sandbox
        ]
      }
    )
  }

  Capybara::Selenium::Driver.new(app, options)
end

# javascript_driverに上で登録したremote_chromeを指定する
Capybara.javascript_driver = :remote_chrome

# Capybaraはtestのためにサーバーを起動する。rails-rspecを用いているなら、Railsが起動する。
# 以下のコマンドが実行されるイメージ
# rails s -b {Capybara.server_host} -p {Capybara.server_port}
# `Capybara.server_host`にサーバーが起動するhostを指定する。別のホストのブラウザからアクセス可能にするため、`0.0.0.0`を指定する。
# `Capybara.server_port`にサーバーがlistenするportを指定する。portを指定しないとランダムなポートで起動するので適当な値を指定する必要がある。
# ref: https://github.com/teamcapybara/capybara/blob/a5b5a04d81e1138d6904e33ac176227d04aacce9/lib/capybara.rb#L98-L99
Capybara.server_host = '0.0.0.0'
Capybara.server_port = '9999'

# `Capybara.app_host`に`chrome`コンテナで動作するブラウザにアクセスしてほしいurlを指定する
# Capybaraが立ち上げるサーバーのURLを指定すれば良い。ただし、`chrome`コンテナが解決できるようなURLを指定する必要がある。
# `visit`メソッドに相対パスが渡された時、この値がBase URLになる。
# つまり、`visit('/hoge')` = `visit("#{Capybara.app_host}/hoge")`
# ref: https://www.rubydoc.info/gems/capybara/Capybara%2FSession:visit
# `IPSocket.getaddress(Socket.gethostname)`は自身のipアドレスを返す。
# ref: https://github.com/teamcapybara/capybara/blob/a5b5a04d81e1138d6904e33ac176227d04aacce9/lib/capybara.rb#L75
Capybara.app_host = "http://#{IPSocket.getaddress(Socket.gethostname)}:#{Capybara.server_port}"

おわりに

以上の設定をすればCapybaraによるE2Eテストが動く環境ができる。

Discussion

kota0919kota0919

dockerコンテナ内でのSystemSpec実行でエラーが出て上手くいきませんでしたが、こちらの記事で
テスト時のエラーが解消されました!助かりました。ありがとうございます😊