3
1

既存Railsアプリをdocker化したらRSpec走らん問題【初学者向け】

Posted at

既存のrailsアプリをdocker化するとローカルでエラーなく走っていたRSpecsystem specのテストが何一つまともに走ってくれず、修正した内容の備忘録となります。
どなたかのお力になれば嬉しいです。

プログラミング初学者なので、内容に誤り等ある可能性があります
誤りがありましたら教えてくださると幸いです

環境
ruby 3.2.2
Ruby on Rails 7.0.8
Docker 24.0.2

エラーその1

docker compose run web bundle exec rspecを実行すると

1.1) Failure/Error: visit root_path
          
          Selenium::WebDriver::Error::WebDriverError:
            unable to connect to /root/.cache/selenium/chromedriver/linux64/122.0.6261.57/chromedriver 127.0.0.1:9515

解決のためにしたこと

Gemfileからwebdriverの記述をコメントアウト

Gemfile抜粋
group :test do
  gem 'capybara'
  gem 'selenium-webdriver'
  # gem 'webdrivers'
end

docker上でテストを行う際は、Seleniumの公式Dockerイメージであるseleniarm/standalone-chromiumを使用します。このイメージにはブラウザとそれに対応するwebdriverがすでに含まれているためwebdriversを使用する必要はありません。

ブラウザが動作するためのコンテナを作成

docker-compose.yml:抜粋
  web:
  #省略
    depends_on:
      - db
      - selenium_chrome

  selenium_chrome:
    image: seleniarm/standalone-chromium
    ports:
      - 4444:4444

selenium_chromeコンテナを追加
私はM1 Macを利用しているためimageにはseleniarm/standalone-chromiumを使用しています
https://qiita.com/mejiro03/items/76f7080b3ab25cbee8e4
https://qiita.com/se_yataro/items/4a741658495cf43df552

capybara.rbを作成

Capybaraの設定をカスタマイズするためspec/support/capybara.rbを作成

capybara.rb
RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :remote_chrome
    Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
    Capybara.server_port = 4444
    Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}"
  end

  config.before(:each, type: :system, js: true) do
    driven_by :remote_chrome
    Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
    Capybara.server_port = 4444
    Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}"
  end
end

# Chrome
Capybara.register_driver :remote_chrome do |app|
  url = ENV['SELENIUM_DRIVER_URL']
  options = ::Selenium::WebDriver::Chrome::Options.new
  options.add_argument('no-sandbox')
  options.add_argument('headless')
  options.add_argument('disable-gpu')
  options.add_argument('window-size=1680,1050')

  Capybara::Selenium::Driver.new(app, browser: :remote, url: url, options: options)

rail_helper.rbの修正

rails_helper.rb抜粋
# デフォルトでコメントアウトされているので、コメントを外す
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

これを外すことでreqire "rails_helper"とテストファイル(hoge_spec.rb)に記述したときspec/support配下のファイルが自動的に読み込まれます。

エラーその2

     Failure/Error: avatar.variant(resize_to_fit: [400, 400]).processed
     
     LoadError:
       Could not open library 'vips.so.42': vips.so.42: cannot open shared object file: No such file or directory.
       Could not open library 'libvips.so.42': libvips.so.42: cannot open shared object file: No such file or directory.
       Searched in <system library path>, /usr/lib, /usr/local/lib, /opt/local/lib

解決のためにしたこと

docker環境にvipsのインストール

gemimage_processingを使用していましたが、docker環境にもvipsをインストールしなければならない
Dockerfileに以下の記述を追加して再度docker compose up --buildを実行

Dockerfile
RUN apt-get update -qq && apt-get install -y --no-install-recommends libvips42

エラーその3

hoge_spec.rbでcapybaraのusing_sessionを使用して2つのセッションを用いてテストコードを書いていたら起きたエラー

     2.3) Failure/Error: Unable to infer file and line number from backtrace
          
          Selenium::WebDriver::Error::InvalidSessionIdError:
            invalid session id
     2.4) Failure/Error: Unable to infer file and line number from backtrace
          
          Selenium::WebDriver::Error::InvalidSessionIdError:
            invalid session id

解決のためにしたこと

selenium_chromeコンテナのセッション上限数を拡張

こちらの記事に書かれている通り公式デフォルトでは、SE_NODE_MAX_SESSIONS 環境変数によって、コンテナごとに 1 つのセッションのみが実行されるように設定されている。と記述されている
そのためdocker-compose.ymlファイルを以下のように修正した

docker-compose.yml抜粋
  selenium_chrome:
    image: seleniarm/standalone-chromium
    environment:
      - SE_NODE_MAX_SESSIONS=2 #有効なセッション数を2つに拡張
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true #オーバーライドの設定を有効に
    ports:
      - 4444:4444

エラーその4

エラーその3が無事解決し、using_sessionを使用したテストコードも無事に成功したので、hoge_spec.rbに記述している全てのテストをまとめて走らせたら起きたエラー

          Selenium::WebDriver::Error::UnknownError:
            unknown error: session deleted because of page crash
            from unknown error: cannot determine loading status
            from tab crashed
              (Session info: chrome-headless-shell=121.0.6167.160)
     1.2) Failure/Error: Unable to infer file and line number from backtrace
          
          Selenium::WebDriver::Error::InvalidSessionIdError:
            invalid session id

解決のためにしたこと

Dockerコンテナに割り当てるリソース量を増やす

docker-compose.yml抜粋
selenium_chromeコンテナのメモリのリソース量を拡張
  selenium_chrome:
    image: seleniarm/standalone-chromium
    shm_size: 256m #メモリ不足を解消
    environment:
      - SE_NODE_MAX_SESSIONS=2
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true
    ports:
      - 4444:4444```dockerfile:docker-compose.yml

参考記事

https://peno022.hatenablog.com/entry/docker-rails7-rspec-configuration-for-system-spec
https://nekonenene.hatenablog.com/entry/selenium-3-to-4-system-spec-net-read-timeout
https://zenn.dev/mitsuaki/articles/d2772bb8a8cd6e
https://zenn.dev/felmy/articles/0f534f8f7bee49

3
1
0

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
3
1