Skip to content

Instantly share code, notes, and snippets.

@kyohei-shimada
Last active February 12, 2023 23:49
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyohei-shimada/e2eab68242b628917eb2 to your computer and use it in GitHub Desktop.
Save kyohei-shimada/e2eab68242b628917eb2 to your computer and use it in GitHub Desktop.
Capybaraを使う上で気をつけること

Capybaraを使う上で気をつけること

アンチパターンとか,ハマりどころとか

expect(page).to have_content 'hogheoge'

expect(page).to have_content 'hogehoge'

page内にhogehogeというテキストが存在するかどうかを確認するために上記のようなコードを書く場合があるが, 検索対象がページ全体になり,ノイズが混ざる可能性がある.さらにもし見つからなかった場合にpage内のテキスト全体がエラーログに表示されてしまいわかりづらい. 下記のように出来る限り要素を絞ると良い

expect(find('#target_content').text).to eq 'hogehoge'

allに注意

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)

not_toと否定形のassertの違い

!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')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment