アンチパターンとか,ハマりどころとか
expect(page).to have_content 'hogehoge'
page内にhogehogeというテキストが存在するかどうかを確認するために上記のようなコードを書く場合があるが, 検索対象がページ全体になり,ノイズが混ざる可能性がある.さらにもし見つからなかった場合にpage内のテキスト全体がエラーログに表示されてしまいわかりづらい. 下記のように出来る限り要素を絞ると良い
expect(find('#target_content').text).to eq 'hogehoge'
elements = all(".target-class")
上記のように,指定した条件にマッチする要素をすべてとるときに以下のようにallを使うととれる. findなどのように要素が見つからなかった場合,見つかるまでcapybaraがwaitをしてくれるが,allは見つからなければその時点で空配列を返す. そのためJSで現れるエレメントやページを読み込んですぐallを使うときれいいに取れない場合がある
- 1つしか要素を期待しない場合はfindを使う(2つ以上要素が見つかるか,ひとつも見つからなければエラーになる)
- allでいくつの要素を期待するかをオプションで渡せるのでそれをつかう.
# 指定した個数に当てはまらない場合は,当てはまるまでしばらく待ってくれる
# 待ってもダメだったらエラーになる
page.assert_selector('p#foo', :count => 4)
page.assert_selector('p#foo', :maximum => 10)
page.assert_selector('p#foo', :minimum => 1)
page.assert_selector('p#foo', :between => 1..10)
!page.has_xpath?('a')
page.has_no_xpath?('a')
公式ドキュメントにもあるが,上記2つは同じではない. 前述の通り,capybaraはエレメント検索時に,条件に一致しなければ,一致するまで一定時間まってくれるようになっている. そのため,上記コード1行目はhave_xpathで'a'を探し,見つかればtrueみつからなければ 見つかるまでしばらく待って最終的に見つからなければ falseを返す.それの反転なので,結果として'a'を探し見つかればfalse, 見つかるまで待って最終的に見つからなければtrueとなる 一方2行目はhave_xpathで'a'を探し,見つかれば 見つからなくなるまでしばらく待って最終的に見つかれば trueを返し,見つからなければfalseを返す.
言葉でいうとややこしいが,要素が見つかることを期待する,見つからないことを期待するかで肯定形のassertと否定形のassertを使いわければよい
expect(page).to have_xpath('a')
expect(page).to have_no_xpath('a')
ちなみに,Capybaraのmatcherはそのあたりを吸収してくれるため,以下のコードは機能的には等価になるらしいが, ややこしいので出来る限りtoは肯定形を使うのが無難かな?
expect(page).not_to have_xpath('a')
expect(page).to have_no_xpath('a')