"Отказаться от подключения" с помощью ChromeDriver, Capybara & Docker Compose

Я пытаюсь сделать переход от PhantomJS к Chrome Headless и немного запутался. Для локального тестирования я использую Docker Compose для запуска всех зависимых сервисов. Чтобы предоставить Google Chrome, я использую изображение, которое объединяет и его, и ChromeDriver вместе, обслуживая его на порту 4444. Затем я свяжу его с контейнером для приложения следующим образом в этом упрощенном файле docker-compose.yml:

web:
    image: web/chrome-headless
    command: [js-specs]
    stdin_open: true
    tty: true
    environment:
        - RACK_ENV=test
        - RAILS_ENV=test
    links:
        - "chromedriver:chromedriver"

chromedriver:
    image: robcherry/docker-chromedriver:latest
    ports: 
        - "4444"
    cap_add: 
        - SYS_ADMIN
    environment:
        CHROMEDRIVER_WHITELISTED_IPS: ""

Затем у меня есть файл spec/spec_helper.rb, который загружает тестовую среду и связанные с ней инструменты. Я определяю драйвер :headless_chrome и указываю его на локальную привязку ChromeDriver; http://chromedriver:4444. Я уверен, что верно следующее:

Capybara.javascript_driver = :headless_chrome

Capybara.register_driver :chrome do |app|
    Capybara::Selenium::Driver.new(app, browser: :chrome)
end

Capybara.register_driver :headless_chrome do |app|
    capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
    chromeOptions: { args: %w[headless disable-gpu window-size=1440,900] },
)

Capybara::Selenium::Driver.new app,
    browser: :chrome,
    url: "http://chromedriver:4444/",
    desired_capabilities: capabilities
end

Мы также используем видеомагнитофон, но я настроил его, чтобы игнорировать любые подключения к порту, используемому ChromeDriver:

VCR.configure do |c|
    c.cassette_library_dir = 'spec/vcr_cassettes'
    c.default_cassette_options = { record: :new_episodes }
    c.ignore_localhost = true
    c.allow_http_connections_when_no_cassette = false
    c.configure_rspec_metadata!
    c.ignore_hosts 'codeclimate.com'
    c.hook_into :webmock, :excon

    c.ignore_request do |request|
        URI(request.uri).port == 4444
    end
end

Я запускаю службы с помощью Docker Compose, который запускает тестовый бегун. Команда в значительной степени такова:

$ bundle exec rspec --format progress --profile --tag 'broken' --tag 'js' --tag '~quarantined'

После небольшого ожидания я столкнулся с первым неудавшимся тестом:

  1) Beta parents code redemption:  redeeming a code on the dashboard when the parent has reached the code redemption limit does not display an error message for cart codes
     Failure/Error: fill_in "code", with: "BOOK-CODE"

     Capybara::ElementNotFound:
       Unable to find field "code"
     # ./spec/features/beta_parents_code_redemption_spec.rb:104:in `block (4 levels) in <top (required)>'

Все спецификации имеют одинаковую ошибку. Итак, я запускаю в контейнер, чтобы запускать тесты самостоятельно и захватывать HTML, на котором он тестирует. Я сохраняю его локально и открываю его в своем браузере, чтобы его приветствовали на следующей странице ошибок Chrome. Казалось бы, ChromeDriver не оценивает спецификацию HTML, потому что он не может ее достичь, поэтому он пытается запустить тесты с этой страницы ошибок.

Учитывая приведенную выше информацию, что я делаю неправильно здесь? Я ценю любую помощь, поскольку уход от PhantomJS разрешит нам столько головных болей.

Большое вам спасибо заранее. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

введите описание изображения здесь

Ответ 1

Проблема, с которой вы сталкиваетесь, заключается в том, что Capybara по умолчанию запускает привязку AUT до 127.0.0.1, а затем сообщает драйверу, что запрос браузера совпадает с этим. В вашем случае, однако, 127.0.0.1 не там, где приложение работает (с точки зрения браузеров), поскольку оно находится в другом контейнере, чем в браузере. Чтобы исправить это, вам нужно установить Capybara.server_host на любой внешний интерфейс "веб-контейнера" (который доступен из контейнера "хромированная решетка" ). Это заставит Capybara привязать AUT к этому интерфейсу и сообщить драйверу, чтобы браузер запрашивал его.

В вашем случае это, вероятно, означает, что вы можете указать 'web'

Capybara.server_host = 'web'