読者です 読者をやめる 読者になる 読者になる

社内勉強会で "PHP Application E2E with Capybara" という話をした

社内勉強会で Capybara の話をしたので,発表資料と実際に試行錯誤しながらプロトタイプを実装したときに学んだ細かなポイントなどをまとめておこうと思う.

発表タイトルを "PHP Application E2E with Capybara" にした通り,一般的なユースケースである Rails Application + Capybara ではなく,PHP Application + Capybara の実現可能性を見極めるのを目的として調べた.Capybara 自体は Rails のライブラリではないため,問題なく PHP Application にも適用できるはずなんだけど,PHP 関連で一部ハマったところがあって,発表後にメンバーにアドバイスを頂いて解決の糸口が見つかりそうな気もする.

とは言え,PHP Application + RSpec + Capybara + Poltergeist で Headless な E2E が実現できることがわかって学びがあった.個人的にも凄く勉強になったし,チームが Selenium で苦労している課題に対して良い提案ができたのではないかなと思っている.

発表資料

ディレクトリ構造

アプリケーションのルートディレクトリ直下に integrations ディレクトリを用意して Capybara 関連のファイルを全て置くようにした.RSpec と Capybara だけじゃなくて,ActiveRecord でデータベースに接続できるようにしたり,thoughtbot/factory_girl · GitHub で Fixture を投入できるようにもしている.support/macros.rb に関しては Rails の慣習?として Capybara で使うヘルパーメソッドを書くために用意した.

app
integrations
├── Gemfile
├── Gemfile.lock
├── database.yml
└── spec
    ├── factories
    │   └── users.rb
    ├── login.rb
    ├── models
    │   └── user.rb
    ├── support
    │   └── macros.rb
    └── spec_helper.rb

Gemfile

RSpec 関連とデータベース関連とデバッグ関連の Gem を使うようにした.

source 'https://rubygems.org'

gem 'rspec'
gem 'capybara'
gem 'poltergeist'

gem 'mysql2'
gem 'activerecord'
gem 'activesupport'
gem 'factory_girl'

gem 'pry'
gem 'awesome_print'
gem 'launchy'

spec_helper.rb

require 'rubygems'

require 'capybara/rspec'
require 'capybara/poltergeist'

require 'active_record'
require 'active_support/core_ext'

require 'yaml'
require 'awesome_print'

require 'factory_girl'

# ヘルパーを使えるようにする
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }

# ActiveRecord のモデルを require する
Dir[File.dirname(__FILE__) + '/models/*.rb'].each { |file| require file }

# データベース接続をできるように
dbconfig = YAML::load(File.open('database.yml'))
ActiveRecord::Base.establish_connection(dbconfig['development'])

# アクセスするベース URL を定義する
# もし Basic 認証が必要なら `https://${user}:${password}@example.com` の形式で定義する
Capybara.app_host = 'https://192.168.33.10'

# Headless で Poltergeist を使う
Capybara.default_driver = :poltergeist
Capybara.javascript_driver = :poltergeist

# 待機時間を5秒に
Capybara.default_max_wait_time = 5

# console.log を捨てる
# SSL 関連でエラーが出ないようにする
Capybara.register_driver :poltergeist do |app|
  options = {
    phantomjs_logger: Logger.new('/dev/null'),
    phantomjs_options: [
      '--ignore-ssl-errors=yes',
      '--ssl-protocol=any'
    ]
  }
  Capybara::Poltergeist::Driver.new(app, options)
end

# factory_girl を更新できるようにする
RSpec.configure do |config|
  config.include Capybara::DSL
  config.before(:all) do
    FactoryGirl.reload
  end
end

macros.rb

def screenshot
  page.save_screenshot "./tmp/#{Time.now.strftime('%Y%m%d-%H%M%S')}.png", full: true
end

def o
  save_and_open_page
end

Rails 以外で Capybara を使うときの注意点

テストコードの describetype: :feature を設定する必要がある.Capybara のドキュメントにも書いてあった.

If you are not using Rails, tag all the example groups in which you want to use Capybara with :type => :feature.

require 'spec_helper'

describe 'ログインする', type: :feature, js: true do
(中略)
end

PhantomJS のオプション

PhantomJS のオプションを指定して console.log を捨てたり,SSL エラーを回避したりした.

Capybara.register_driver :poltergeist do |app|
  options = {
    phantomjs_logger: Logger.new('/dev/null'),
    phantomjs_options: [
      '--ignore-ssl-errors=yes',
      '--ssl-protocol=any'
    ]
  }
  Capybara::Poltergeist::Driver.new(app, options)
end

困ってること

発表資料の P22-25 に書いた通り,FuelPHP だと E2E の環境面で課題があって困っていた.具体的には Rails だと rake spec で WEBrick が起動するから実環境が無くてもテストを動かすことができるけど,現状の環境だと E2E 専用の Nginx + php-fpm 環境が必要で,うまく解決できなかった.ローカルや CI など複数の環境で自由に E2E を流せる環境ってどうやって作れば良いんだろう.

Oil Server

最新版の FuelPHP だと Oil Server と言うビルトインサーバがあるらしく WEBrick のように使える可能性があるとアドバイスをもらった.現状 FuelPHP のバージョンが低くて使えないけど,調べてみる価値はありそう.

まとめ

今回も勉強会駆動学習(プレッシャー駆動学習)で頑張って Capybara + Poltergeist にそこそこ詳しくなれた気がする.E2E テストは凄く重要だけど Selenium だとツライ場面も多くて,Headless の重要性を改めて感じている.Rails + Capybara はよく聞く構成だけど,PHP + Capybara は比較的珍しいのかなと思っていて,経験のある人ともっと議論や相談をしたいなーなんて思っている.今よりもっと便利に楽しく E2E テストを書ける環境を構築できるように引き続き頑張るぞ!!!