RSpec - フィーチャスペックを導入する
everyday Rails の「第6章 フィーチャスペックでUIをテストする」の復習用まとめ。
書籍から内容の増減があります。
本章の前提
フィーチャースペックとは、モデルとコントローラが 他の モデルやコントローラとうまく一緒に動作することを確認するテストのこと。受入テストや統合テストと呼ばれることもある。
目次
- Capybaraをインストールする
- フィーチャスペックの基本
- CapybaraのDSL
- セレクタのスコープを制限する
- フィーチャスペックをデバッグする
- JavaScript を使った操作をテストする
- ヘッドレスドライバを使う
- JavaScript の完了待ち時間を伸ばす
Capybaraをインストールする
Rails 5.1以降であれば標準でインストールされている。
5.0以前の場合はgemの指定が必要。
group :test do gem 'capybara', '~> 2.15.2' end
テストスイートでCapybaraを読み込む設定
spec/rails_helper.rb
# ... require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! require 'capybara/rspec' # ←追加する # ...
フィーチャスペックの基本
スペック作成
bin/rails generate rspec:feature projects
ログインからプロジェクト追加までをテスト
spec/features/projects_spec.rb
scenario " user creates a new project" do 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" # click_buttonは起動されたアクション完了前に次の処理へ移ることがある # そのため、expect {} 内部でテストして完了を待ってから、countチェック 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
CapybaraのDSL
簡易DSL
scenario"workswithallkindsofHTMLelements"do # ページを開く 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.gif" # 指定した CSS に一致する要素が存在することを検証する expect(page).to have_css "hsubheading" # 指定したセレクタに一致する要素が存在することを検証する expect(page).to have_selector "ul li" # 現在のパスが指定されたパスであることを検証する expect(page).to have_current_path "/projects/new" end
セレクタのスコープを制限する
<div id="node"> <a href="http://nodejs.org">click here!</a> </div> <div id="rails"> <a href="http://rubyonrails.org">click here!</a> </div>
下のclick here!をクリックしたい場合
within "#rails" do click_link "click here!" end
特定の要素を検索して操作する
# 要素を指定して値を取得 language = find_field("Programming language").value expect(language).to eq "Ruby" # 要素を指定して操作 find("#fine_print").find("#disclaimer").click find_button("Publish").click
Capybara DSL 公式doc
フィーチャスペックをデバッグする
save_and_open_pageを置くことで、
tmp/capybara以下にresponseのhtmlファイルが吐き出される
scenario "guest adds a project" do visit projects_path save_and_open_page click_link "New Project" end
デバッグ作業が終わったら、save_and_open_pageメソッドを削除する
自動で開きたい場合はLaunchy Gemを追加する
Gemfile
group:test do gem 'capybara', '~> 2.15.2' gem 'launchy', '~> 2.4.3' end
JavaScript を使った操作をテストする
JSに依存するテストをする場合は下記の対応が必要。
- js: true というオプションを渡す。
- selenium-webdriver gemを使う。(Rails 5.1でデォルトでインストール)
- Capybaraがselenium-webdriverに対して、Chromeを使うように設定。
とりあえず実装例を見て、設定は後述。
scenario "user toggles a task", js: true do user = FactoryBot.create(:user) project = FactoryBot.create(:project, name: "Rspec tutorial", owner: user) task = project.tasks.create!(name: "Finish Rspec tutorial") visit root_path click_link "Sign in" fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Log in" click_link "Rspec tutorial" check "Finish Rspec tutorial" expect(page).to have_css "label#task_#{task.id}.completed" expect(task.reload).to be_completed uncheck "Finish Rspec tutorial" expect(page).to_not have_css "label#task_#{task.id}.completed" expect(task.reload).to_not be_completed end
Capybaraがselenium-webdriverでChromeを使うように設定
RSpec関連の設定ファイルをspec/supportディレクトリに配置できるようにする
spec/rails_helper.rb
の下記該当部分のコメントを外す
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
Capybaraの設定
spec/support/capybara.rb
Capybara.javascript_driver = :selenium_chrome
ChromeDriverのインストール
Chrome とやりとりするインターフェース
group :test do gem 'capybara', '~> 2.15.4' # 2.13.x系だとエラー出るので注意! gem 'selenium-webdriver' gem 'chromedriver-helper' gem 'launchy', '~> 2.4.3' end
ヘッドレスドライバを使う
Circle CIやJenkinsでのテスト時にブラウザが起動するのを避けたい。
解決策1 - Chrome のヘッドレスモードを使う(version 59.0以上)
spec/support/capybara.rb
# Capybara.javascript_driver = :selenium_chrome # ←削除 Capybara.javascript_driver = :selenium_chrome_headless # ←追加
最新情報は公式docで
JavaScript の完了待ち時間を伸ばす
Capybaraはデフォルトでボタン出現まで2秒待つ
これを長くする方法は2つ
※処理の完了を待つためにRubyのsleepメソッドはNG
設定ファイルに記述
ただし、テスト全体が遅くなるリスクがあるので注意
pec/support/capybara.rb
Capybara.default_max_wait_time = 15
スペックで実装時に指定
scenario "run sareally slow process" do using_wait_time(15) do # ここにテスト実装 end end