CapybaraでSinatraアプリをテストする
このブログはSinatraで作っていて、テストはRack::Testで書いてたのだけど、思い立ってCapybaraで書き直した。
Rack::Test vs Capybara?
というのはある種のバグがRack::Testだと漏れちゃうんですよね。例えばフォームをsubmitしたときにビューのtypoで正しいリクエストが飛ばない、みたいなやつ。Rack::TestだとこういうPOSTリクエストに対しこういう挙動をする、は書けるんだけど、ボタンを押したときにどういうPOSTが飛ぶか、はCapybaraでないと書けない。
もっと規模が大きければRack::Testでコントローラのテストを書いて、Capybaraでintegraiton testを書いて…みたいな構成もあり得るけど、このブログの場合は規模が小さいのでCapybaraによるE2Eテストだけあれば良いかなと思う。
以下、Rack::Testから移行するに当たって「これどうするんだろ?」ってなったことをメモしておく。
Basic認証したい
Driverによって指定方法が違うみたい。Rack::TestドライバはBasic認証に対応してなさそう。しかしヘッダを直接指定するという方法があった(参考)。
# https://github.com/yhara/nlog2/blob/a63294a2a1b514e76ac130b2f6400fda8a8436b5/spec/app_spec.rb#L8-L11
def login(username='jhon', password='passw0rd')
encoded_login = ["#{username}:#{password}"].pack('m*')
page.driver.header 'Authorization', "Basic #{encoded_login}"
end
フォームが表示されることを確認したい
have_content("form")…かと思いきや、これはformというテキストが画面に表示されている、という意味なのでタグには反応しない。have_selector("form")が正解。
フォームにデフォルトで入力されていることを確認したい
これもhave_selectorでいける。こんな感じ。
expect(page).to have_selector("input[name='title'][value='#{@valid_posted[:title]}']")
POSTしたい
postメソッドがない、と思ったがCapybaraはE2Eテスト用のライブラリなので、POSTリクエストを直接送るような手段はないのだった。そりゃそうか。その代わりにclick_linkやclick_buttonといったメソッドがあるので、まずvisitで編集画面にアクセスして、フォームに記入してclick_buttonする、みたいな書き方になる。
今回はこんな感じにした。
login
visit '/_edit/'
fill_editor @valid_params
click_button "Save"
fill_editorはcheckメソッドでチェックボックスをオンにしたり、fill_inでテキストを入力したりする。定義は以下。
def fill_editor(params)
check "permanent" if params[:permanent]
fill_in "title", with: params[:title]
fill_in "slug", with: params[:slug]
fill_in "body", with: params[:body]
fill_in "datetime", with: params[:datetime]
end