RSpec Capybara Webkit Xvfb CentOS 要するにRailsでjavascriptをテストしたい

Shunsuke Sawada

RSpec + Capybara のセットアップは簡単でいいんですが、javascriptのテストができません。
いざ本当にウェブサイトやウェブアプリのテストしようと思ったらjavascriptのテストは必須。
それを可能にするには意外にも長い道のりがあるので、まとめておきます。

想定する開発環境はこんな感じ。

macbook dev environment

テストについてよくわからなければ、このチュートリアルで学習。
Ruby on Rails チュートリアル:実例を使って Rails を学ぼう

テスト駆動開発の定義とは、アプリケーションを開発するときに最初にテストを作成し、次にコードを作成することです。この開発手法に慣れるまでには多少時間がかかるかもしれませんが、一度慣れてしまえば大きなメリットを得られます。失敗するテストを最初に書き、テストにパスするコードを次に実装することで、しかるべき振る舞いがテストによって正しく検証されている、という自信が付きます。

道のり

Xvfb

インストール

1
2
3
4
5
6
7
$ yum search Xvfb
===== N/S Matched: Xvfb =====
xorg-x11-server-Xvfb.x86_64 : A X Windows System virtual framebuffer X server.

$ sudo yum groupupdate "X Window System"

$ sudo yum install xorg-x11-server-Xvfb

確認

1
2
3
ディスプレイ番号を環境変数に設定。
$ DISPLAY=:1.0
$ export DISPLAY

Xvfbをディスプレイ番号:1、スクリーン番号:0、幅:1024px、高さ:768px、ビット深度:24bit で起動。

1
2
3
4
5
6
7
8
コマンドの最後に&を付加することにより、バックグラウンドで動かすことができる。
$ Xvfb :1 -screen 0 1024x768x24&

実行中のジョブを表示するには下記.
$ jobs

終了する
$ killall Xvfb

テストとは直接関係ないけど xwd と ImageMagick をインストールしたらスクリーンショットも撮れる。

1
2
3
4
5
6
7
8
9
10
$ yum install ImageMagick
$ yum install xwd

$ xwd -display :1 -root -out test.xwd
-display ディスプレイ番号
-root    ディスプレイ全体を撮る
-out     出力ファイル名

ImageMagickのconvertコマンドでpngに変換。
$ convert test.xwd test.png

Gem

必要なGemをインストールする。

1
2
3
4
5
6
7
8
group :test do
  gem 'selenium-webdriver', '~> 2.35.1' # javascript_driver
  gem 'capybara', :git => 'git://github.com/jnicklas/capybara.git'
  gem 'factory_girl_rails', '4.2.1'
  gem 'database_cleaner' # データベースが絡むテストには必要
  # gem 'capybara-webkit' # デフォルトのjavascript_driverを変更する場合
  gem 'headless' # Railsから簡単にXvfbを起動できる
end

capybara-webkitのインストールにはQTが必要。
※ ページ下部を参照。

1
$ bundle install

spec_helper.rb

spec_helper.rbにいろいろ設定する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  .
  .
  require 'rspec/rails'
  require 'rspec/autorun'
  require 'capybara/rspec'
  require 'capybara-webkit'
  require 'headless'
  require 'database_cleaner'

  RSpec.configure do |config|
    Capybara.javascript_driver = :selenium
    # もしくは、Capybara.javascript_driver = :webkit

    config.before(:suite) do
      # Xvfbを起動するheadlessの設定
      Headless.new(:destroy_on_exit => false).start
    end

    # javascriptテストとスレッドを共有するにはfalseにする
    config.use_transactional_fixtures = false
  .
  .
  end

database_cleaner

spec/support/に database_cleaner.rb というファイルを作成
※ ファイル名はお好みで

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
RSpec.configure do |config|

  # 処理が高速なので、普段はtransactionを使用する
  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  # jsオプションが有効な時のテストはtruncationを使用
  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  # database cleaner の設定

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end

capybara-webkit

javascript_driverをcapybara-webkitすると処理が高速になりました。
javascriptほとんど使っていないテストですけど、結構違う。

selenium: Finished in 1 minute 31.15 seconds
webkit: Finished in 1 minute 11.55 seconds

capybara-webkitのインストールにはQTが必要。
CentOS 6.4の場合は以下の手順。

/etc/yum.repos.d/ にファイル作成

1
$ sudo vi /etc/yum.repos.d/qt.repo

下記をコピペ、保存。

1
2
3
4
5
6
7
8
9
10
11
12
13
[epel-qt48]
name=Software Collection for Qt 4.8
baseurl=http://repos.fedorapeople.org/repos/sic/qt48/epel-$releasever/$basearch/
enabled=1
skip_if_unavailable=1
gpgcheck=0

[epel-qt48-source]
name=Software Collection for Qt 4.8 - Source
baseurl=http://repos.fedorapeople.org/repos/sic/qt48/epel-$releasever/SRPMS
enabled=0
skip_if_unavailable=1
gpgcheck=0
1
2
3
4
5
6
7
8
インストール
yum install qt48-qt-webkit-devel
シンボリックリンク
ln -s /opt/rh/qt48/root/usr/include/QtCore/qconfig-64.h  /opt/rh/qt48/root/usr/include/QtCore/qconfig-x86_64.h
実行
source /opt/rh/qt48/enable

export PATH=/opt/rh/qt48/root/usr/lib64/qt4/bin/${PATH:+:${PATH}}

その他のOS、バージョンは下記参照。
Installing Qt and compiling capybara webkit · thoughtbot/capybara-webkit Wiki · GitHub

テスト

テストの記述自体はこんな感じ。
js: true オプションを忘れずに。

1
2
3
4
5
6
7
describe "User page", js: true do
 before do
   sign_in user
   visit user_path(user)
 end
 it { should have_content('User profile') }
end

以上です。
いろいろとやることがありますが、
一度セットアップするだけなので、頑張りましょー。

参考

thoughtbot/capybara-webkit · GitHub

bmabey/database_cleaner · GitHub

Headless, a Ruby wrapper for Xvfb – gem, headless, Ruby, rubygems, Xvfb – Leonid Shevtsov

Configuring database_cleaner with Rails, RSpec, Capybara, and Selenium | Virtuous Code

RSpecとCapybaraでJavaScript/Ajaxをテストする - Rails 雑感 - Ruby on Rails with OIAX

#gemfile rails 3, rspec-rails, capybara, capybara-webkit, headless in order to run request specs that can test javascript

30
Shunsuke Sawada

おすすめの記事

CakePHP 2.x JSヘルパーでajax通信(ajax helperは使わない)
20
Rails4でQiita投稿ボタンをつくった
18
紙のデザイナーがウェブ開発できるようになるまでに必要なこと
451