Docker環境にSystem Specを導入する

#はじめに
Docer環境でRSpecのSystem Specを導入しようとしたところ、結構ハマったので、備忘録としてまとめます。

まず、Docer環境にSystem Specを実行するためには、いくつか方法があるらしい。
調査をしていると、メジャーな方法は以下の二つ(もっとあるかもしれませんが、、、)

１. Railsが動いているimageにchromeをインストールする方法
２. chrome用コンテナを立ち上げる方法

今回は2の方法でやってみました。

#前提
[Quickstart: Compose and Rails](https://docs.docker.com/compose/rails/)の通りに、Rails on Dockerの環境構築が済んでいる状態とします。
筆者の環境は
- Ruby 2.5.7
- Rails 5.2.4
です。

#docker-compose.ymlを編集する
selenium_chromeのコンテナが立ち上がるようdocker-compose.ymlに追加していきます。
Dockerイメージには[selenium/standalone-chrome](https://github.com/SeleniumHQ/docker-selenium)を使用します。

```docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
      #追加
      - chrome
  #追加
  chrome:
    image: selenium/standalone-chrome:3.141.59-dubnium
    ports:
      - 4444:4444
```

#gemを追加する

```:Gemfile

group :development, :test do
  gem 'rspec-rails'
end

group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
end
```
dockerをbuildして、bundle installします。

```ターミナル
$ docker-compose build
$ docker-compose up -d
```

#rspecの設定
rspecをインストールします。

```ターミナル
$ docker-compose run web rails g rspec:install
```
#headless chromeの設定

spec/rails_helper.rbにheadless chromeの設定を追加していきます。

```/spec/rails_helper.rb
require 'capybara/rspec'

# headless chrome 設定①
Capybara.server_host = Socket.ip_address_list.detect { |addr| addr.ipv4_private? }.ip_address
Capybara.server_port = 3001   ※

Capybara.register_driver :selenium_remote do |app|
  url = "http://chrome:4444/wd/hub"
  opts = { desired_capabilities: :chrome, browser: :remote, url: url }
  Capybara::Selenium::Driver.new(app, opts)
end


 # headless chrome 設定②
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_remote
    host! "http://#{Capybara.server_host}:#{Capybara.server_port}"
  end
end
```
ポイント：
後半部分(# headless chrome 設定②)で、
`js: true`を記述した場合のみ、seleniumドライバーが立ち上がるように設定しています。

ハマったポイント：
`js: true`のテストを走らせたとき、Capybaraがseleniumサーバーを立ち上げて、先ほど設定したchromeコンテナで起動しているchromeを操作します。
しかし、Capybara.server_portを指定する部分（*）で、webコンテナで指定したポートと同じ3000を指定してしまうと、`js: true`のテストを走らせたときに、webコンテナで指定したポートと競合してseleniumサーバーが立ち上がらずエラーとなってしまいます。
そこで、Capybara.server_port = ~~3000~~ 3001
とすることで、競合することなく、無事サーバーが立ち上がり、テストが通るようになりました。

これで準備は整いました。
あとは、テストを実際に走らせるだけです。

#実際にテストを走らせてみる

```spec/system/test_spec.rb
require "rails_helper"

RSpec.describe 'Test', type: :system, js: true do
  example 'サンプルテスト' do
    #ここにテスト内容を記述
  end
end
```
```ターミナル
$ docker-compose exec web bundle exec rpsec
```
これで、テストが通るはずです。

##参考記事
下記の記事を参考にさせていただきました。
ありがとうございます。
- [Docker で RSpec の System Spec を実行するための設定メモ](https://qiita.com/suketa/items/d783ac61c2a3e4c16ad4)
- [Rails + Selenium + DockerでSystemSpecの環境構築](https://qiita.com/ngron/items/f61b8635b4d67f666d75)
- [Rails on Dockerにて、Headless ChromeでSystem Testをやってみた。](https://qiita.com/at-946/items/e96eaf3f91a39d180eb3)