Search code examples
ruby-on-railsrubydockerseleniumgithub-actions

How selenium access capybara server on Github Actions?


I'm creating a personal project with Ruby on Rails.

I'm trying to create a CI with Github Actions + Capybara + Selenium Service. Why selenium service? To make it closer to the project's docker-compose.

First, this is my workflow file:

name: CI
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:14.4
        ports:
          - 5432:5432
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
      selenium:
        image: selenium/standalone-chrome:3.141.59
        ports:
          - 4444:4444
    steps:
      -
        name: Check out repository code
        uses: actions/checkout@v3
      -
        name: 'Create web docker image'
        run: docker build -t web . --target new_release
      -
        name: 'Create database'
        run: docker run --env-file .docker/env_files/.env.ci --network="host" web bin/rails db:create db:migrate
      -
        name: 'Run unit tests'
        run: docker run --env-file .docker/env_files/.env.ci --network="host" web bin/rails test
      -
        name: 'Run system tests'
        run: docker run --env-file .docker/env_files/.env.ci --network="host" web bin/rails test:system

On the last step this error happens:

Selenium::WebDriver::Error::UnknownError: unknown error: net::ERR_CONNECTION_REFUSED

My interpretation is that the selenium service is unable to connect with the capybara server. So, let's talk about the capybara configuration of the project:

# frozen_string_literal: true

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  Capybara.register_driver(:chrome_remote) do |app|
    Capybara::Selenium::Driver.new(
      app,
      browser: :remote,
      url: ENV.fetch("SELENIUM_URL"),
      capabilities: Selenium::WebDriver::Remote::Capabilities.chrome
    )
  end

  Capybara.run_server = true
  Capybara.server = :puma, { Silent: true }
  Capybara.server_host = ENV.fetch("CAPYBARA_SERVER_HOST")
  Capybara.server_port = ENV.fetch("CAPYBARA_SERVER_PORT")

  Capybara.default_driver = :chrome_remote
  Capybara.javascript_driver = :chrome_remote

  Capybara.save_path = Rails.root.join("tmp/capybara")

  driven_by :chrome_remote, using: :chrome, screen_size: [1400, 1400]

  include FactoryBot::Syntax::Methods
end

And finally, the env file used on the ci:

CAPYBARA_SERVER_HOST=localhost
CAPYBARA_SERVER_PORT=4000
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost
RAILS_ENV=test
SELENIUM_URL=http://localhost:4444/wd/hub

I tried not using --network="host", using the name of the services, but using that configuration I was unable to pass "Create database" step. I'm wondering why is not working, I can see the capybara creating the server using my environment variables:

Capybara starting Puma...
* Version 5.6.2 , codename: Birdie's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:4000
* Listening on http://[::1]:4000

But I'm lost, not sure what the connection is being refused. In the local environment, the tests pass perfectly. What do you think?


Solution

  • Instead of using the services + docker, I decided to use docker-compose. The file that did the trick:

    version: "3.7"
    
    services:
      db:
        image: postgres:14.4
        ports:
          - 5432:5432
        env_file:
          - ./.docker/env_files/.env
        healthcheck:
          test: ["CMD-SHELL", "pg_isready"]
          interval: 10s
          timeout: 5s
          retries: 5
        volumes:
          - ./.docker/volumes/postgres_data:/var/lib/postgresql/data
    
      web:
        image: test
        env_file:
          - ./.docker/env_files/.env
        build:
          context: .
        depends_on:
          db:
            condition: service_healthy
        links:
          - db
        ports:
          - 3000:3000
        volumes:
          - .:/opt/test:cached
        stdin_open: true
        tty: true
    
      livereload:
        image: test
        depends_on:
          - web
        ports:
          - 35729:35729
        command: ["bundle", "exec", "guard", "-i"]
        env_file:
          - ./.docker/env_files/.env
        volumes:
          - .:/opt/test:cached
    
      tailwindcsswatcher:
        image: test
        depends_on:
          - web
        ports:
          - 3035:3035
        command: ["bin/rails", "tailwindcss:watch"]
        env_file:
          - ./.docker/env_files/.env
        volumes:
          - .:/opt/test:cached
        tty: true
    
      selenium:
        image: selenium/standalone-chrome:3.141.59
        ports:
          - 4444:4444
    
    volumes:
      postgres_data:
    

    Now the ci.yml using the docker-compose:

    name: CI
    on: push
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          -
            name: Check out repository code
            uses: actions/checkout@v3
          -
            name: 'Create docker-compose file'
            run: cp .docker/docker-compose.dev.yml docker-compose.yml
          -
            name: 'Create env file'
            run: cp .docker/env_files/.env.dev .docker/env_files/.env
          -
            name: Build web container
            run: docker-compose build web selenium
          -
            name: 'Create database'
            run: docker-compose run --rm web bin/rails db:create db:migrate
          -
            name: 'Start container'
            run: docker-compose up -d web selenium
          -
            name: 'Run unit tests'
            run: docker-compose exec -T web bin/rails test
          -
            name: 'Run system tests'
            run: docker-compose exec -T web bin/rails test:system