Rails5.2でSeleniumとChromedriveのコンテナーでテストを実行する

@yszk0123 の[記事](https://qiita.com/yszk0123/items/840f16ed388fb52b0e21)を（ほとんど）参考に自分が以前作った[Rails5.2 AdminLTE docker](https://qiita.com/jb-vasseur/items/0f3e8569bb847bdba4fb)を改良してJS込みのブラウザーテストができるようにしてみました。

![nicolas-thomas-540353-unsplash.jpg](https://qiita-image-store.s3.amazonaws.com/0/260796/47d9d0aa-2cfa-0aab-0216-ca617bd0bbcf.jpeg)


# seleniumとchromeをコンテナーで利用する

以下のレポジトリ（ブランチ`selenium-headless-chrome`）にスクリプトを格納しています。

https://gitlab.com/jvasseur/rails-adminLTE-docker/tree/selenium-headless-chrome

まず、新しいRailsプロジェクトを作成します。

```shell
> docker-compose -f docker/docker-compose.create-rails.yml build --no-cache
> docker-compose -f docker/docker-compose.create-rails.yml up --force-recreate
```

今回新しく用意された`docker-compose.test.yml`ファイルにネットワークとselenium&chromeイメージベースのサービスが追加されています。

```yaml:docker-compose.test.yml
version: '3'
services:
  db:
    image: mysql:5.7.22
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    environment:
      MYSQL_DATABASE: rails-app
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3306:3306'
    hostname: db
    volumes:
      - ../mysqldata:/var/lib/mysql
    networks:
      rails-app-network:
        aliases:
          - rails-app-db.com

  web:
    build:
      context: ..
      dockerfile: ./docker/Dockerfile
    command: ../scripts/start_rails.sh
    image: rails-app:0.0.1
    volumes:
      - ..:/app
    environment:
      APP_NAME: rails-app
      RAILS_ENV: development
      DB_HOST: 'db'
      DB_PORT: '3306'
      DB_USER: 'root'
      DB_PASSWORD: 'password'
      DB_NAME: 'rails-app'
      MYSQL_DATABASE: 'rails-app'
      RAILS_LOG_TO_STDOUT: "yes"
      WEB_CONCURRENCY: 1
      RAILS_MAX_THREADS: 5
    ports:
      - "3000:3000"
    links:
      - db
    depends_on:
      - 'db'
    networks:
      rails-app-network:
        aliases:
          - rails-app-web.com

  chrome:
    container_name: chrome
    image: selenium/standalone-chrome-debug:3.9.1-actinium
    ports:
      - 4444:4444
      - 5900:5900
    networks:
      rails-app-network:
        aliases:
          - rails-app-chrome.com
networks:
  rails-app-network:
```

コンテナーを起動し、seleniumのコンテナーをVNC経由でアクセスできることを確認します(パスワードは`secret`)。

```shell
docker-compose -f docker/docker-compose.test.yml build
docker-compose -f docker/docker-compose.test.yml up
```

```shell
open vnc://localhost:5900
```

# Rails側の設定でテスト実行時にseleniumコンテナーにつなげる

`Gemfile`に新しいGem`rspec-rails`が追加されました。
また、`chromedriver-helper`が不要になったため削除しました。

```ruby:Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.4.2'

gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'tzinfo-data'
gem 'unicorn'

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'capybara', '>= 2.15', '< 4.0'
  gem 'selenium-webdriver'
  gem 'rspec-rails'
end

group :development do
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end
```

そしてRspecの初期化を行っています。

`rails generate rspec:install`

最後に`rails_helper.rb`にcapybaraとseleniumの設定を追加しています。 

```ruby:rails_helper.rb
...

# Add additional requires below this line. Rails is not loaded until this point!
require "capybara/rails"
require "selenium/webdriver"

ActiveRecord::Migration.maintain_test_schema!

if ENV["LAUNCH_BROWSER"]
  Capybara.configure do |config|
    config.server_host = "rails-app-web.com"
    # config.server_port = 3000
    config.javascript_driver = :selenium_chrome_headless
  end

  Capybara.register_driver :selenium_chrome_headless do |app|
    Capybara::Selenium::Driver.new(
      app,
      browser: :remote,
      desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
        chromeOptions: {
          args: [
            "window-size=1024,512",
          ]
        }
      ),
      url: "http://rails-app-chrome.com:4444/wd/hub",
    )
  end
else
  Capybara.register_driver :selenium_chrome_headless do |app|
    Capybara::Selenium::Driver.new(
      app,
      browser: :chrome,
      options: Selenium::WebDriver::Chrome::Options.new(
        args: [
          "headless",
        ],
      ),
    )
  end
end

...
```

# Running the tests

コンテナーが起動の状態でDBの初期化・マイグレーション・データ投入を行います。

```shell:
docker exec docker_web_1 rails db:create
docker exec docker_web_1 rails db:migrate
docker exec docker_web_1 rails db:seed
```

これでテストが実行可能になります。環境変数`LAUNCH_BROWSER`を設定した場合にのみseleniumコンテナーを利用します。

```shell:
> docker exec -it docker_web_1 sh
$ export LAUNCH_BROWSER=true
$ bundle exec rspec
```

<img width="719" alt="Screen Shot 2018-07-06 at 17.29.36 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/260796/b1f0ad82-06b0-c316-7043-ad58fd0e39d5.png">


40-50秒掛かります、これはpumaの起動時間に関係しているようにみえます。
この構成でE2Eテストが実現可能になったかと思いますがもう少しテストを実践して改善ポイントを見つけていきたいと思います。