Stan's blog

Ruby on Rails Capybara Docker Selenium Rspec Gitlab CI/CD

E2E Тестирование в Rails 7.1.2 в GitLab Runner CI/CD, с помощью Selenium-Webdriver (4.8.6), Capybara (3.39.2), Docker Compose

20 января 2024

Kandinsky: Результат генерации по запросу "E2E Тестирование в Rails 7.1.2 в GitLab Runner CI/CD", стиль: anime
Настройка Docker Compose

Для тестирования E2E Capybara запускает webdriver. Сейчас Selenium предлагает широчайшие возможности для тестирования. Для своего маленького проекта я взял всего лишь chrome. Суть такова, что когда Gitlab Runner запускает тестирование, есть отдельный докере с chrome. Например, так:
version: '3.0'
services:
  browser:
    image: seleniarm/standalone-chromium
    shm_size: 2gb
    volumes:
      - /dev/shm:/dev/shm

  app:
    image: my_blog_development
    build:
      context: .
      dockerfile: prod.Dockerfile
      args:
        - PRECOMPILEASSETS=YES
    environment:
      - RAILS_ENV=test
      - SELENIUM_HUB_HOST=browser
    links:
      - db
      - browser
    depends_on:
      db:
        condition: service_healthy
      browser:
        condition: service_started
...
SELENIUM_HUB_HOST говорит, собственно, название хоста (совпадает с название сервиса), где вертится chrome. Docker Compose разрешит это имя в IP-адрес сам.

Настройка Rails

Можно и закрепить версии, а то вдруг опять поменяют интерфейс как относительно недавно
# Gemfile
group :development, :test do
  gem 'capybara' #, "~> 3.39.2"
  gem 'selenium-webdriver' #, "~> 4.8.6"
end
Путь файлы конфигурации подгружаются сами
# spec/rails_helper.rb
Rails.root.glob('spec/support/**/*.rb').sort.each { |f| require f }
Добавить файл конфигурации Capybara
# spec/support/capybara_config.rb
require 'capybara'
require 'selenium-webdriver'

def ensure_selenium_running!
  timer = Capybara::Helpers.timer(expire_in: 20)
  begin
    TCPSocket.open(ENV['SELENIUM_HUB_HOST'], 4444)
  rescue StandardError
    if timer.expired?
      raise 'Selenium is not running. ' \
          "You can run a selenium server easily with: \n" \
          '  $ docker-compose up -d selenium_firefox'
    else
      puts 'Waiting for Selenium docker instance...'
      sleep 1
      retry
    end
  end
end

Capybara.register_driver :remote_chrome do |app|
  options = Selenium::WebDriver::Options.chrome
  options.add_argument('no-sandbox')

  if ENV['SELENIUM_NO_HEADLESS'].present? 
    options.add_argument('--start-maximized') # чтобы было видно окно браузера для отладки тестов
  else
    options.add_argument('--headless')
    options.add_argument('--window-size=1400,1400')
  end

  options.add_argument('--ignore-gpu-blocklist')
  options.add_argument('--enable-features=VaapiVideoDecode')

  ## failback options # если на скриншотах будут черные квадраты вместо сайта
  #options.add_argument('--disable-gpu')
  #options.add_argument('--disable-software-rasterizer')

  ensure_selenium_running!

  Capybara::Selenium::Driver.new app,
    browser: :remote,
    capabilities: options,
    url: "http://#{ENV['SELENIUM_HUB_HOST']}:4444/wd/hub"
end

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :remote_chrome

    Capybara.app_host = "http://#{IPSocket.getaddress(Socket.gethostname)}:3000"
    Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
    Capybara.server_port = 3000
    Capybara.server = :puma, { Silent: true }
  end
end
А вот и самый простой тест
# spec/features/index_spec.rb
require 'rails_helper'

RSpec.describe 'User', type: :system do
  it 'visits page' do
    visit "/"
    expect(page).to have_text('Stan\'s blog')
  end
end

А как отлаживать тесты?

Для удобства пробросим порты и отключим аутентификацию для VNC. Да, в хаб встроен VNC сервер и даже вэб VNC клиент
# docker-compose.devel.yml - Docker Compose для разработки
  browser:
    image: seleniarm/standalone-chromium
    shm_size: 2gb
    environment:
      - SE_VNC_NO_PASSWORD=true
      - VNC_NO_PASSWORD=1
    ports:
      - "5900:5900" #for VNC access
      - "4444:4444" #for webdriver access
      - "7900:7900" #for web VNC access
    volumes:
      - /dev/shm:/dev/shm
  app:
    environment:
      - RAILS_ENV=development
      - BUNDLE_WITHOUT=""
      - SELENIUM_HUB_HOST=browser
      - SELENIUM_NO_HEADLESS=1 # чтобы видно было окно браузера
...
Теперь можно подключиться localhost:4444 или localhost:7900 и посмотреть за ходом выполнения теста и полазить в  DevTools (sleep 60 в тесте поможет продлить удовольствие от созерцания страницы в режиме выполнения теста)