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


@yszk0123記事を(ほとんど)参考に自分が以前作ったRails5.2 AdminLTE dockerを改良してJS込みのブラウザーテストができるようにしてみました。

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

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

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

> 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イメージベースのサービスが追加されています。

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)。

docker-compose -f docker/docker-compose.test.yml build
docker-compose -f docker/docker-compose.test.yml up
open vnc://localhost:5900

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

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

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の設定を追加しています。

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の初期化・マイグレーション・データ投入を行います。

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コンテナーを利用します。

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

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