前回の続き
#システムスペックとは
テストには、コントローラスペックやモデルスペックのような、単一のモデル、コントローラが期待通りに動作するかチェックする単体テストと、複数のモデル、コントローラを統合したプログラム全体の挙動をチェックする統合テストがあります。
RSpecでは、この統合テストの一つとしてシステムスペックが提供されています。(似たテストでフィーチャースペックもありますが、Rails5.1以降では非推奨になりました。)
システムスペックは、統合テストの中でも、特にUIのテストとして有効です。
#準備
ブラウザの操作をシュミレートするためにCapybaraをインストールします。これを使うと、テスト内でリンクをクリックしたり、画面の表示を検証したりできます。
##Capybaraのインストール
Rails5.0以降では、Capybaraはデフォルトでインストールされているので、もしインストールされていない場合はGemfileからインストールしましょう。
group :test do
gem 'capybara'
end
$ bundle install
##設定
テストでシステムスペックとCapybaraを使えるようにするために、設定に追記します。
#追記
require 'capybara/rspec'
RSpec.configre do |config|
#追記
config.before(:each, type: :system) do
driven_by :rack_test
end
config.before(:each, type: :system, js: true) do
driven_by :selenium_chrome_headless
end
#システムスペックの基本
準備が終わったので、まずはスペックファイルを作っていきましょう。
$ rails g rspec:system projects
Capybaraではvisitやfill_in、click_linkといったメソッドが提供されており、アプリで必要な機能のシナリオを簡単に書くことができます。
require 'rails_helper'
RSpec.describe "Projects", type: :system do
scenario "user creates a new project" do #itと同じexampleの起点
user = FactoryBot.create(:user)
#ログイン操作
visit root_path
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
#プロジェクト作成
expect {
click_link "New Project"
fill_in "Name", with: "Test Project"
fill_in "Description", with: "Trying out Capybara"
click_button "Create Project"
expect(page).to have_content "Project was successfully created"
expect(page).to have_content "Test Project"
expect(page).to have_content "Owner: #{user.name}"
}.to change(user.projects, :count).by(1)
end
end
システムスペックでは、ユーザーがブラウザ上で行う操作に近いテストができます。
#Capybaraのメソッド
上記のスペック以外にも、Capybaraは多くのメソッドを提供しています。
その中でも頻出のものを紹介します。
ページを開く
visit "/fake/page"
リンクまたはボタンのラベルをクリックする
click_on "A link or button label"
チェックボックスのラベルをチェックする
check "A checkbox label"
チェックボックスのラベルのチェックを外す
uncheck "A checkbox label"
ラジオボタンのラベルを選択する
choose "A radio button label"
セレクトメニューからオプションを選択する
select "An option", from: "A select menu"
ファイルアップロードのラベルでファイルを添付する
attach_file "A file upload label", "/some/file/in/my/test/suite.f"
指定した CSS に一致する要素が存在することを検証する
expect(page).to have_css "h2#subheading"
指定したセレクタに一致する要素が存在することを検証する
expect(page).to have_selector "ul li"
現在のパスが指定されたパスであることを検証する
expect(page).to have_current_path "/projects/new"
##曖昧さ回避
ページ内に指定したセレクタが複数該当してCapybaraに「曖昧ですよ」と怒られる場合は、スコープを制限することで解決できます。
#指定したclassかidを持つリンクテキストをクリック
within "#id or .class" do
click_link "click here!"
end
#指定したclassかidを持つタグをクリック
find('div.class input').click
#ページ全体で最初に該当するタグをクリック
first(input).click
#ページ全体で最後に該当するタグをクリック
last(input).click
#システムスペックのデバッグ
コンソールの出力からテストの結果を見ることができますが、Capybaraではヘッドレスブラウザ(UIを持たないブラウザ)を使ってRailsがブラウザに返したHTMLを見ることができます。
scenario "guest adds a project" do
visit projects_path
save_and_open_page #この時点で返されるHTMLが保存される
click_link "New Project"
end
save_and_open_pageでHTMLが保存されるので、それをブラウザ上で開くことで確認できます。
この機能は便利ですが、毎回手作業でファイルを開くのは面倒なので、Launchy gemをインストールして自動的に開くようにします。
group :test do
gem 'launchy'
end
$ bundle install
#JavaScriptを使った操作のテスト
##準備
Railsでデフォルトでインストールされているselenium-webdriver gemによってテストで使うJavaScriptドライバを指定しますが、初期設定のFireFoxのままだと互換性問題があるようなので、Chromeを使うよう設定を変更します。
Capybaraの設定用ファイルを分けたいので、rails_helper.rbのファイル読み込み設定から始めていきます。
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
Capybara.javascript_driver = :selenium_chrome_headless
CI環境の場合、テスト実行中にブラウザのウィンドウが新しく開くのは望ましくないため、そういった用件に泰雄するためにCapybaraではヘッドレスドライバが使えるようになっています。ここでは、Chromeのヘッドレスモードを使ってテストを実行するように設定しています。
最後にWebdriver gemをインストールします。
group :test do
gem 'webdrivers'
end
##テスト
js: trueオプションを渡すことで、JavaScriptを使った操作をテストすることができます。
scenario "test name", js: true do
#テスト内容
end
##JavaScript待ち時間の設定
Capybaraではデフォルト設定の場合、処理の結果取得の待ち時間が2秒になっていますが、処理が間に合わずにテストが失敗することがあります。
これを回避するために待ち時間を任意で設定することもできます。
Capybara.default_wait_time = 15 #15秒に設定
テストスイート全体でこの設定が適用されますが、テスト実行が必要以上に遅くなる可能性もあるため、必要に応じてusing_wait_timeを都度使うことも視野に入れると良いでしょう。
scenario "test" do
using_wait_time(15) do #このブロック内のみ待ち時間15秒になる
#テスト内容
end
end