ぺのめも

Web開発を勉強中。学んだことや思ったことなど

Docker + Rails 7 + RSpec で System Spec を実行するための設定

はじめに

Docker環境でRailsのWebアプリケーションを開発し始めた際、RSpecのSystem Specを実行するために必要な設定の全貌がなかなか分からず。
大ハマリしたので、手順を残しておきます。

Gemfile.lockのバージョン情報:

開発には VSCode Remote Container を利用しています。

デフォルトで入っている 'webdrivers' gem は削除する

webrdrivers を利用すると、Docker環境ではなくローカル(=ホスト)側にブラウザを探しにいってしまうようで、Webdrivers::BrowserNotFoundのエラーが発生します。

Gemfile:

# test以前は省略
group :test do
  gem 'capybara'
  gem 'launchy'
  gem 'selenium-webdriver'
  # gem 'webdrivers' ← これは削除する
end

webrdriversのgemが読み込まれると発生してしまうエラー:

# gem 'webdrivers' を削除しないで bundle exec rspec を実行

Failure/Error:
       driven_by :selenium, using: :headless_chrome, options: {
         browser: :remote,
         url: ENV.fetch('SELENIUM_DRIVER_URL'),
       }
Webdrivers::BrowserNotFound:
Failed to determine Chrome binary location.

参考:

github.com

補足

参考リンク先ではgem 'webdrivers', require: !ENV['SELENIUM_REMOTE_URL']という修正方法になっています。
Docker環境とローカル環境の両方で動かせるようにしたいという事情がある場合、gem 'webdrivers', require: !ENV['SELENIUM_DRIVER_URL']にしておくことで、「環境変数を設定しているコンテナで利用する場合はwebdriversを読み込まない」という形にできるからのようです。
自分の場合はDocker環境で使えればOKなので、gem 'webdrivers'の行ごと削除しています。

ちなみに、そもそもGemfileのrequire ~~~が何をしているのかについては、こちらの記事が分かりやすかったです。

masuyama13.hatenablog.com

Chromeのコンテナと、Railsのコンテナをネットワークで接続する

docker-compose.ymlを修正する必要があります。 下記のように、appのコンテナとselenium_chromeのコンテナを、同じネットワークで指定します。

version: '3'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile

    volumes:
      - ../..:/workspaces:cached

    ### 追記 ###
    networks:
      ktg-net:

  selenium_chrome:
    image: selenium/standalone-chrome-debug
   
    ### 追記 ###
    networks:
      ktg-net:
  
  db:
   image: postgres:15.1
    # 中略

### 追記 ###
networks:
  ktg-net:

volumes:
  postgres-data:

ネットワーク接続ができていない状態だと、下記のエラーが発生しました。

Failure/Error: visit root_path
          
          SocketError:
            Failed to open TCP connection to selenium_chrome:4444 (getaddrinfo: Name or service not known)

利用するドライバーを設定する

RSpecの設定ファイル(/spec/rails_helper.rbなど)に設定を追加する必要があります。
自分の場合は設定を下記のようにspec/support/配下に切り出しているため、spec/support/capybara.rbのファイルにドライバーの設定を書きました。

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

spec/support/capybara.rb:

# frozen_string_literal: true

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium, using: :headless_chrome, options: {
      browser: :remote,
      url: ENV.fetch('SELENIUM_DRIVER_URL')
    }
    Capybara.server_host = 'app'
  end
end

以下、設定内容について解説します。

driven_by :selenium, using: :headless_chrome

ドライバの種類として:seleniumを指定し、利用するブラウザに:headless_chromeを指定しています。
(利用するコンテナイメージも合わせて変更すれば、ブラウザには:headless_firefoxなどを指定することも可能です。)

driven_byのドキュメント:

api.rubyonrails.org

なお、driven_byでドライバとして設定できるのは、現時点で:selenium, :poltergeist, :webkit, :cuprite, :rack_testの5種類のようです。 github.com

options の設定

options: {
      browser: :remote,
      url: ENV.fetch('SELENIUM_DRIVER_URL')
    }

ローカルではなくリモート環境のブラウザを利用するため、browser: :remoteを指定しています。
また、リモートに存在するドライバーのURLを指定する必要があるため、ここではdocker-compose.yml環境変数として設定したものを参照しています。
環境変数に設定せずurl: 'http://selenium_chrome:4444/wd/hub'と直接書いても問題なく動きます。)

github.com

docer-compose.ymlを修正し、appコンテナに環境変数を追加:

version: '3'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile

    # 中略

    ### 追記 ###
    environment:
      - SELENIUM_DRIVER_URL=http://selenium_chrome:4444/wd/hub 

# 以下略

Capybara.server_host

テストアプリケーションが外部ホストからアクセスされる場合に設定が必要とのこと。

server_host (String = "127.0.0.1") - The IP address Capybara will bind the application server to. If the test application is to be accessed from an external host, you will want to change this to "0.0.0.0" or to a more specific IP address that your test client can reach.

Module: Capybara — Documentation for capybara (3.38.0)

デフォルト値が127.0.0.1のため、何も設定しないとドライバがアプリケーションを見つけられず、エラーが発生します。

# Capybara.server_host の設定をせずに bundle exec rspec を実行

Failure/Error: visit root_path
     
     Selenium::WebDriver::Error::UnknownError:
       unknown error: net::ERR_CONNECTION_REFUSED
         (Session info: headless chrome=94.0.4606.61)

その他参考

qiita.com

qiita.com