🔴CircleCiで、Rails6のRspecのSYSTEMテストを実行する方法【Docker】

# ✅当方の環境
- 開発環境 : Docker
- ruby 2.7.5
- rails 6.1.5
- Circle Ci

# ✅前提条件
:::note warn
「selenium-webdriver」をアプリ（WEB）のコンテナに導入したのではなく、アプリ（WEB）のコンテナとは別の「selenium-webdriver」のDockerコンテナを新しく作成・起動させて、SYSTEMテストを実行した場合に、本記事が有効である
- アプリ（WEB）のコンテナに、直接「Chome-driver」を導入した場合などは、本記事は対象外
- [こちらの記事](https://qiita.com/felmy/items/d4b1334a6adee071ef46)で「selenium-webdriver」を導入した場合は、以降の内容を試してみてください
:::

# ✅概要
:::note alert
Circle Ciで使用する「自分で設定したイメージファイル」と、「自分で設定したDockerのイメージファイル」は、別々でお互いに共有されないため、Circle Ciの環境をDockerのイメージと同じ環境にするためには「.circleci\config.yml」にDockerfileと同じ設定を記載する必要がある。
- そのため、「.circleci\config.yml」に、「selenium-webdriver」を別コンテナで起動させるように、イメージを追加
- そして、ブラウザによるテストのため、javascriptが起動してしまうため、アセッツコンパイルを実施
- しかし、DockerのRubyの元々のイメージには、nodejsが導入されていないため、Circle CIが提供しているイメージ バリアントを使用し、あらかじめRubyのイメージにnodejsが導入されているようイメージを使用する
- 最後に、テスト前に「rake assets:precompile」を実行させる
:::

# ✅よくあるエラー
```
SocketError:
 Failed to open TCP connection to chrome:4444 (getaddrinfo: No address associated with hostname)
          
SocketError:
 Failed to open TCP connection to chrome:4444 (getaddrinfo: No address associated with hostname)

Failure/Error: <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
     
ActionView::Template::Error:
 Webpacker can't find application.js in /home/circleci/*****************/src/public/packs-test/manifest.json. Possible causes:
```

# ✅解決法
- 「.circleci\config.yml」に、CircleCiでも「selenium-webdriver」を使用するように修正する
```diff_ruby:docker-compose.yml
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.2
  heroku: circleci/heroku@1.2.3

jobs:
  build:
    docker:
      - image: cimg/ruby:2.7.5
    working_directory: ~/dev-docker-rails6/src
    steps:
      - checkout:
          path: ~/dev-docker-rails6
      - ruby/install-deps

  test:
    docker:
       #RUBYのイメージに最初から、nodejsを導入するようイメージ バリアントを追加
+     - image: cimg/ruby:2.7.5-node
      - image: circleci/mysql:5.5
        environment:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: app_test
          MYSQL_USER: root
       #selenium-webdriverを別コンテナで起動させるため、seleniumのイメージ追加
-      - image: selenium/standalone-chrome-debug:latest
-        name: chrome
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      APP_DATABASE_HOST: "127.0.0.1"
      RAILS_ENV: test
    working_directory: ~/dev-docker-rails6/src
    steps:
      - checkout:
          path: ~/dev-docker-rails6
      - ruby/install-deps
      - run:
          name: Database setup
          command: bundle exec rails db:migrate
       #javasriptでエラーが発生するため、テスト前にアセッツコンパイルを実施
       #アセッツコンパイルをするために、RUBYのイメージにnode-jsが必要
+      - run:
+          name: webpacker compile
+          command: bundle exec rake assets:precompile
      # - run:
      #     name: Database setup
      #     command: bundle exec  rails db:seed
      - run:
          name: test
          command: bundle exec rspec

  deploy:
    docker:
      - image: cimg/ruby:2.7.5
    steps:
      - checkout
      - setup_remote_docker:
          version: 19.03.13
      - heroku/install
      - run:
          name: heroku login
          command: heroku container:login
      - run:
          name: push docker image
          command: heroku container:push web -a $HEROKU_APP_NAME
      - run:
          name: release docker image
          command: heroku container:release web -a $HEROKU_APP_NAME
      - run:
          name: database setup
          command: heroku run bundle exec rake db:migrate RAILS_ENV=production -a $HEROKU_APP_NAME
      # - run:
      #     name: database seed
      #     command: heroku run bundle exec rake db:seed RAILS_ENV=production -a $HEROKU_APP_NAME

workflows:
  version: 2
  build_test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only: main
```

# ✅参考ファイル
- [CircleCI での Yarn (npm の代替) の使用](https://circleci.com/docs/ja/2.0/yarn/)
- [CircleCIのシステムスペックをselenium dockerを利用する](https://qiita.com/tomoronn3/items/ee66d4bdcf1f21a352c2)

# ✅当方の環境の各種設定ファイル
## 🔴Gemfile
```ruby:Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.7.5'

gem 'rails', '~> 6.1.5'
gem 'mysql2', '~> 0.5'
gem 'puma', '~> 5.0'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
gem 'bootsnap', '>= 1.4.4', require: false

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  #Rspecのため導入
  gem 'pry-rails'
  gem "rspec-rails", "~> 4.0.1"
  gem 'factory_bot_rails', '~> 5.0'
end

group :development do
  gem 'web-console', '>= 4.1.0'
  gem 'rack-mini-profiler', '~> 2.0'
  gem 'listen', '~> 3.3'
  gem 'spring'
end

group :test do
  #RspecのSystemテストのため導入
  gem 'capybara', '~> 3.28'
  gem 'selenium-webdriver', '~> 3.142'

end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'rails-i18n'

```
## 🔴Dockerfile
```ruby:Dockerfile
FROM ruby:2.7.5

ENV RAILS_ENV=production

#apt-keyとdevconfのエラー対策
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV DEBCONF_NOWARNINGS=yes

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update -qq \
  && apt-get install -y nodejs yarn mariadb-client vim
WORKDIR /app
COPY ./src /app
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install

COPY start.sh /start.sh
RUN chmod 744 /start.sh
CMD ["sh", "/start.sh"]
```

## 🔴docker-compose.yml
```ruby:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - ./src/db/mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: Asia/Tokyo
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ./src:/app
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
      SELENIUM_DRIVER_URL: http://selenium_chrome:4444/wd/hub
    depends_on:
      - db
      - chrome
  chrome:
    image: selenium/standalone-chrome-debug
    ports:
      - 4444:4444
```

## 🔴config.yml
```ruby:.circleci\config.yml

version: 2.1
orbs:
  ruby: circleci/ruby@1.1.2
  heroku: circleci/heroku@1.2.3

jobs:
  build:
    docker:
      - image: cimg/ruby:2.7.5
    working_directory: ~/dev-docker-rails6/src
    steps:
      - checkout:
          path: ~/dev-docker-rails6
      - ruby/install-deps

  test:
    docker:
      - image: cimg/ruby:2.7.5-node
      - image: circleci/mysql:5.5
        environment:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: app_test
          MYSQL_USER: root
      - image: selenium/standalone-chrome-debug:latest
        name: chrome
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      APP_DATABASE_HOST: "127.0.0.1"
      RAILS_ENV: test
    working_directory: ~/dev-docker-rails6/src
    steps:
      - checkout:
          path: ~/dev-docker-rails6
      - ruby/install-deps
      - run:
          name: Database setup
          command: bundle exec rails db:migrate
      - run:
          name: webpacker compile
          command: bundle exec rake assets:precompile
      # - run:
      #     name: Database setup
      #     command: bundle exec  rails db:seed
      - run:
          name: test
          command: bundle exec rspec

  deploy:
    docker:
      - image: cimg/ruby:2.7.5
    steps:
      - checkout
      - setup_remote_docker:
          version: 19.03.13
      - heroku/install
      - run:
          name: heroku login
          command: heroku container:login
      - run:
          name: push docker image
          command: heroku container:push web -a $HEROKU_APP_NAME
      - run:
          name: release docker image
          command: heroku container:release web -a $HEROKU_APP_NAME
      - run:
          name: database setup
          command: heroku run bundle exec rake db:migrate RAILS_ENV=production -a $HEROKU_APP_NAME
      # - run:
      #     name: database seed
      #     command: heroku run bundle exec rake db:seed RAILS_ENV=production -a $HEROKU_APP_NAME

workflows:
  version: 2
  build_test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only: main

```
## 🔴database.yml
```ruby:config\database.yml
# MySQL. Versions 5.5.8 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db

development:
  <<: *default
  database: app_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: app_test
  host: <%= ENV.fetch("APP_DATABASE_HOST") { 'DB' } %>

# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
#   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
#   production:
#     url: <%= ENV['MY_APP_DATABASE_URL'] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
production:
  <<: *default
  database: <%= ENV['APP_DATABASE'] %>
  username: <%= ENV['APP_DATABASE_USERNAME'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
  host: <%= ENV['APP_DATABASE_HOST'] %>

```