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

前回の記事、
[Dockerを使ってHeadless Chromeを動かしてみる](http://qiita.com/dd511805/items/dfe03c5486bf1421875a)で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で必要な
項目を渡します。

```ruby: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の時の処理を同じように
記述します。

```ruby: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](http://qiita.com/meguroman/items/41ca17e7dc66d6c88c07)にあるとの同じエラーは当然発生するためにCapybaraでも以下のような
コードはエラーになってしまいます。

```ruby: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)を定義しておいて、
テストを書き換えることで、エラーを回避しつつ、テストが
実行できます。

```ruby: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
```