29. 受入テストの Javascript 対応

旧システムでは Rails の掟通り、edit, new などでページが遷移してしまい、自分が何の作業をしていたのかがわからなくなるという不満が多かった。そのため、最近作ったページは edit や new の画面も index や show と同じ内容を表示するような作り込みをしており、かなり実装の負担になっていた(旧システムは Javascript を極力使用しないという制約をかけていたため)。

実際、ページ遷移してしまうとわかりにくいというのはわかるが、Javascript で DOM をいじり回すのも実装の負担になる。そこで、今回は基本的な CRUD なタイプのページは modal ダイアログを全面に使用していこうと思っている。最近、あるテーブルに対して一連の作業を実装し、一部の教員にテストしてもらった。特に異論がないようなので、この形で実装を進めていく。このページの実装の説明は随分先の話になるが、システム周りの話は先に書いておかないと説明が矛盾するので、先に説明する。

これまで受入テストは Javascript に対応していない rack_test を使っていた。これだと通常の GET アクセスになってしまい、テストがエラーになる。今回は、Capybara のJavascript に対応した poltergeist をインストールしてみる。

Phantom.js のインストール

Gemfile を修正する前に、依存する Phantom.js をシステムにインストールする。Mac については、brew でインストールできる。

brew install phantomjs

Lunux のサーバ側も ansible-playlist を修正し、polyerguist をインストールした。

poltergeist のインストール

その後 Gemfile を修正し、bundle する。何も考えずに入れていた 'selenium-webdriver' は削除した。

  gem 'poltergeist', '~> 1.6.0'

Poltergeist の設定を spec/turnip_spec.rb に記載する(Rails 3.2 に Turnip Capybara Poltergeist を導入してみるを参考にした)。

require 'capybara'
require 'capybara/rspec'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist

# web driver
Capybara.register_driver :poltergeist_debug do |app|
  Capybara::Poltergeist::Driver.new(app, :inspector => true)
end

step ファイルの追加

今後書く feature ファイルでは、最初にブラウザの準備をするstepを背景として実行することにした。この部分で上記 Poltergeist の初期化をする。

step %(ブラウザの準備をする) do
  Capybara.current_driver = :poltergeist_debug
end

これで通るかと思ったら、データベースが初期化されていなかった。spec/rails_helper.rb の use_transactional_fixtures を false に直していなかったためであった。DatabaseRewinder を設定するときに忘れたらしい。今まで racktest だったから気づかなかったらしい。

  config.use_transactional_fixtures = false

せっかく Poltergeist を入れたので、トラブル時に画面を確認できるように「画面キャプチャ」の step を作っておく。spec/acceptance/steps/common_steps.rb に追加した。

# その時点のwebページの画面キャプチャを撮る
step %(画面をキャプチャ) do
  page.save_screenshot('screen.png', :full => true)
end

その他の step の追加

いろいろと受入テストを追加していて、テーブルのそれぞれの行に対する存在確認やリンククリックが必要になった。xpath を使うと範囲を狭めることができるようなのでいくつか step を追加してみた。せっかくなので紹介しておく。

# 指定行の表示テキスト存在確認
step %(:targetの行に:textと表示されていること) do |target, text|
  within :xpath, "//tr[td='#{target}']" do
    expect(page).to have_content(text)
  end
end

# 指定行の表示テキスト不在確認
step %(:targetの行に:textと表示されていないこと) do |target, text|
  within :xpath, "//tr[td='#{target}']" do
    expect(page).not_to have_content(text)
  end
end

# 指定行のリンクをクリック (textはリンク文字列かid)
step %(:targetの行の:textリンクをクリックする) do |target, text|
  within :xpath, "//tr[td='#{target}']" do
    click_link text
  end
end

今日はここまで。

written by iHatenaSync