Rails6のシステムテストがDockerコンテナ上で実行できない。


# Railsでアプリ作ったので、Dockerコンテナ上でシステムテストを実行してみよう。
[以前書いた記事](https://qiita.com/hanaitama-kaz/items/5b68b9c665f75020bcd4)の続きで、Dockerの勉強がてら、デスクトップの無いコンテナ上でシステムテストなんてできるのか、試してみたところ、ハマりにハマったのでやっぱり記事に残しておこうと思います。

# 参考にしたもの。
[CapybaraのReadMe](https://github.com/teamcapybara/capybara#configuring-and-adding-drivers)
[ヘッドレス Chrome ことはじめ](https://developers.google.com/web/updates/2017/04/headless-chrome?hl=ja)

# 環境
主なコンポーネントのバージョンは以下の通りになります。
詳しくは後ろの方にDockerファイルを掲載させていただきます。
Google Chrome 83.0.4103.61 
Rails 6.0.3
Ruby 2.6.5


# 事象
システムテストを実行してみると以下のようなエラーが発生します。
色々書いてますが、"Chrome has crashed."とあるので、chromeが起動しないのでしょう。

```
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally.
  (unknown error: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
```

# 切り分け
本当にchromeが起動しないのか、コマンドラインで試してみました。

```bash:shell
# ヘッドレスモードでamazon.comにいってみます。
$ google-chrome --headless https://www.amazon.com/ --dump-dom > hoge.txt

# =>こんなメッセージが出てきてしまい、動きません。 
# Running as root without --no-sandbox is not supported. See https://crbug.com/638180.

# では、--no-sandboxをつけて試してみます。
$ google-chrome --headless --no-sandbox https://www.amazon.com/ --dump-dom > hoge.txt

# => hoge.txtの中身は誌面の都合上割愛させていただきますが、
#    ちゃんとamazonのトップページと思しきレスポンスが書き込まれます。
```

# 解決方法
切り分けた結果から、chrome起動時のオプションが変更できれば解決できると思い、色々調べた結果、railsのtest/application_system_test_case.rbを以下の通り書き換えることで解決できました。

```ruby:test/application_system_test_case.rb
require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  # 元々書かれていた以下のコードは破棄
  # driven_by :selenium, using: :chrome, screen_size: [1400, 1400]

  # ここから追加 ====>
  # ドライバを新しい名前で追加します。
  Capybara.register_driver :selenium_chrome_headless_nosandbox do | app |
    # Chrome用のオプションを設定
    options = Selenium::WebDriver::Chrome::Options.new;
    options.add_argument('--headless');
    options.add_argument('--no-sandbox');

    # 当初、以下のオプションを付けないと動かないと勘違いしていたのですが、不要なようです。
    # options.add_argument('--disable-gpu');

    # 作成したオプションを指定してchrome用のドライバを生成します。
    driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: options);

  end

  # 作ったドライバをdriven_byで指定してあげます。
  driven_by :selenium_chrome_headless_nosandbox

  # <=== ここまで追加

end

```

# おまけの使用環境
## 構築に使用したDockerファイル
一応、環境構築に使ったDockerファイルも公開させていただきます。

```Dockerfile:Dockerfile
# ruby 2.6.5のベースイメージを利用しました。
FROM ruby:2.6.5

# nodejsのLTS版を自動でインストールしてみたくてnvmを入れておきました。
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

# nodejsのLTS版をインストール(他に良い書き方ないだろうか。。)
RUN ["/bin/bash", "--login", "-c", "nvm install --lts"]

# aptのダウンロード先リポジトリにgoogleを追加するため、keyを追加
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -

# aptのダウンロード先リポジトリにdl.google.com/linux/chrome/debを追加
RUN echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list

# apt-getでchrome等をインストール
RUN apt-get update -qq && apt-get install -y npm google-chrome-stable

# yarnをインストール
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
RUN ["/bin/bash", "--login", "-c", "yarn install --check-files"]

# bundlerとrailsのgemをインストール
RUN gem install bundler
RUN gem install rails

```

## コンテナ起動方法
上記DockerファイルにはENTRYPOINTやCMDを指定してないので、そのままでは起動できません。
/bin/bashを引数に入れて起動してください。
起動例を以下に記載しておきます。

```bash:shell
# 適当なディレクトリに、上のDockerfileをおきます。
# 配置イメージはこのような感じです。
$ ls -l .
total 8
-rw-r--r--  1 dareka  staff  1049  6  2 14:20 Dockerfile

# Dockerイメージをビルドします。
$ docker build --tag testimage .

# イメージが作れたのでコンテナ起動
$ docker container run -it --name rortest testimage /bin/bash
```