Rails: minitest & GitLab CI
Tags: rails, devops, ruby, testing
Published: 2020-10-09 15:44:13

Hi everybody, this post is the first of a serie I'd like to write, revolving around rails and CI/CD.

In this one I'll show you how to setup a proper CI for your new rails project.

I tried to give you the simplest example in order to focus on what's interesting, the configuration, I hope you'll find it useful.

Here is the repo alongside this article: https://gitlab.com/mpressen/rails_with_gitlab_ci

___
#### *Init project*
```
$ rails new rails_with_gitlab_ci --database=postgresql
$ cd rail_with_gitlab_ci
$ rails db:create db:migrate
$ rails server
```

![Yay! You're on Rails](https://dev-to-uploads.s3.amazonaws.com/i/p990pzrizto9kfxr8xt7.png)


Perfect time to commit and push our code :
```
$ git add -A
$ git commit -m 'init rails project with postgresql'
$ git remote add origin git@gitlab.com:$(username)/rails_with_gitlab_ci.git
$ git push --set-upstream origin master
```

___
#### *Add failing tests*

Let's create a failing controller test :
```ruby
# test/controllers/dummy_controller_test.rb

require 'test_helper'

class DummyControllerTest < ActionDispatch::IntegrationTest
  test "the truth" do
    assert false
  end
end
```

And a failing system test :
```ruby
# test/system/dummy_system_test.rb

require 'application_system_test_case'

class DummySystemTest < ApplicationSystemTestCase
  test 'the truth' do
    assert false
  end
end
```

___
#### *Setup gitlab CI*

```yaml
# .gitlab-ci.yml

image: ruby

stages:
  - test

tests:
  stage: test
  services:
  - postgres
  - name: selenium/standalone-chrome
    alias: chrome
  cache:
    paths:
      - apt-cache
      - node_modules
      - vendor/bundle
  variables:
      DB_HOST: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: root
      SELENIUM_REMOTE_URL: http://chrome:4444/wd/hub
      RAILS_ENV: test
      BUNDLE_PATH: vendor/bundle
  before_script:
    - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
    - 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 -o dir::cache::archives="$APT_CACHE_DIR" install -yqq yarn
    - yarn install
    - bundle install
    - bundle exec rails db:setup
  script:
    - bundle exec rails test  test/*

```

```ruby
# config/database.yml

...
#
default: &default
  ...
  host: <%= ENV["DB_HOST"] %>
  username: <%= ENV["POSTGRES_USER"] %>
  password: <%= ENV["POSTGRES_PASSWORD"] %>
...
```

This config caches back and front dependencies for speed and computation cost (a must).

My favorite part is the use of a third docker image, `selenium/standalone-chrome` that avoids a pain point (chrome versions ...) some might have encountered before. With this config, it's another container that runs an headless chrome navigator on system tests.

```ruby
# test/application_system_test_case.rb

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  if ENV['SELENIUM_REMOTE_URL']
    Capybara.server_host = '0.0.0.0'
    driven_by :selenium, using: :headless_chrome, screen_size: [800, 800], options: { url: ENV['SELENIUM_REMOTE_URL'] }
  else
    driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
  end

  def setup
    if ENV['SELENIUM_REMOTE_URL']
      net = Socket.ip_address_list.detect(&:ipv4_private?)
      ip = net.nil? ? 'localhost' : net.ip_address
      Capybara.app_host = "http://#{ip}"
    end
    super
  end
end
```

```ruby
group :test do
  ...
  gem 'webdrivers', require: !ENV['SELENIUM_REMOTE_URL']
end
```

Let's try it !

```
$ git add -A
$ git commit -m 'setup gitlab CI'
$ git push
```

![CI failure](https://dev-to-uploads.s3.amazonaws.com/i/4mbpvmog9thui9ehmbfu.png)

Now, let's replace `assert false` by `assert true` in our dummy tests, commit and push.

![CI success](https://dev-to-uploads.s3.amazonaws.com/i/tbi30prrt2dezqtgqf4o.png)

Yeah !