Help us understand the problem. What is going on with this article?

CapybaraからHeadless Chromeを動かす環境をDockerで構築する

More than 1 year has passed since last update.

前回の記事、
Dockerを使ってHeadless Chromeを動かしてみるでDockerからHeadless Chromeを使う環境が出来たので、これをベースにCapybaraからHeadless Chromeを使う環境を構築してみます。

Docker Imageの構築

前回からの変更点としては、chromium-chromedriverの追加とRuby関連のライブラリの追加です。nokogiri等も入れてbunlde install時に
困らないようにしておきます。

FROM alpine:edge

RUN apk add --update \
            udev \
            ttf-freefont \
            chromium \ 
            chromium-chromedriver

RUN mkdir /noto

ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto 

WORKDIR /noto

RUN unzip NotoSansCJKjp-hinted.zip && \
    mkdir -p /usr/share/fonts/noto && \
    cp *.otf /usr/share/fonts/noto && \
    chmod 644 -R /usr/share/fonts/noto/ && \
    fc-cache -fv

WORKDIR /
RUN rm -rf /noto

RUN apk add --update ruby \
                     ruby-bundler \ 
                     ruby-irb \ 
                     ruby-dev \ 
                     build-base \
                     libxml2-dev \
                     libxslt-dev \
                     libffi-dev \
                     zlib-dev
RUN gem install nokogiri --no-doc --no-ri
RUN gem install ffi --no-doc --no-ri

ENTRYPOINT tail -f /dev/null

Capybaraのインストール

前段落で構築したイメージをコンテナを起動して、Capybaraをインストールします。
下記のようなGemfileを作成してbundle installを行います。

# frozen_string_literal: true
source "https://rubygems.org"

gem "rspec"
gem "json"
gem "capybara"
gem "selenium-webdriver"

Capybaraの設定

ここはseleniumを使うときと大きな違いはありませんが、
webdriverからchromeに渡すオプションにheadlessで必要な
項目を渡します。

spec_helper.rb
require 'capybara/rspec'
require 'selenium-webdriver'

RSpec.configure do |config|
  config.include Capybara::DSL
end

base_args = %w{headless no-sandbox disable-gpu}
Capybara.register_driver :headless_chromium do |app|  
  args = base_args.dup << "--window-size=1900,1080"
  caps = Selenium::WebDriver::Remote::Capabilities.chrome(                       
    "chromeOptions" => {                                                         
      'binary' => "/usr/bin/chromium-browser",
      'args' => args                              
    }                                                                            
  )                                                                              
  driver = Capybara::Selenium::Driver.new(                                       
    app,                                                                         
    browser: :chrome,                                                            
    desired_capabilities: caps                                                   
  )                                                                              
end                  
Capybara.default_driver = :headless_chromium 

chomeOptionsのbinaryのところには、Headless Chomeのバイナリ
のパスを指定します。今回の環境では/usr/bin/chrominm-browserが
Headless Chomeのパスになっていました。

Capybaraを使ったテストの実行

ここは通常のCapybara+Seleniumの時の処理を同じように
記述します。

my_spec.rb
Capybara.app_host = 'http://qiita.com/'

describe "http://qiita.com" do

  before do
    visit '/'
  end

  it "we can see top page" do
    expect(page).to have_content('Qiitaは、プログラマのための
技術情報共有サービスです。')
    expect(page.driver.browser.current_url).to match /qiita/
    page.save_screenshot('screenshot.png')
  end
end

ただし、[2017/6最新]RubyとSeleniumでHeadless chromeを動かす on Ubuntu/Linuxにあるとの同じエラーは当然発生するためにCapybaraでも以下のような
コードはエラーになってしまいます。

fill_in.rb
Capybara.app_host = 'http://qiita.com/'

describe "http://qiita.com" do

  before do
    visit '/'
  end

  it "input identity" do
    fill_in('identity', :with => "dd511805")
    expect(page.driver.browser.current_url).to match /qiita/
  end
end

javascriptでのキー入力はできるようなので、この場合では
fill_inとは別の関数(下の例ではfill_in_val)を定義しておいて、
テストを書き換えることで、エラーを回避しつつ、テストが
実行できます。

fill_in.rb
module HeadlessAction
  def fill_in_val(id, options)
    with = options.delete(:with)
    page.execute_script "document.getElementById(\"#{id}\").value = \"#{with}\";"
  end
end

RSpec.configure do |config|
  config.include HeadlessAction
end
Capybara.app_host = 'http://qiita.com/'

describe "http://qiita.com" do

  before do
    visit '/'
  end

  it "input identity" do
    fill_in_val('identity', :with => "dd511805")
    expect(page.driver.browser.current_url).to match /qiita/
  end
end
dd511805
a-hikkoshi
当社は、親会社である株式会社エイチームの経営理念をそのままに、引越しの比較サービス開始以降、大切にしてきた「三方よし」の理念を基本として、世の中に求められるサービスの創造を目指します。 一緒に働けるエンジニアを募集しております。下記URLよりご応募ください。 https://bit.ly/3lwf7QJ
https://hikkoshi.a-tm.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away