セキュリティ系の勉強、その他開発メモとか雑談. GithubはUnity触っていた頃ものがメイン Twitterフォローもよろしくです

【Rspec, Capybara】dt, dd要素を取得 ~ 隣の要素を取得

タイトル通りの内容です。 フィーチャーテストをする際に、dd, dtの値を関連づけて取ることでテストをわかりやすく、書きやすくしたいと思いました。

問題

<dl>
  <dt id="family-name" class="label">f_name</dt>
  <dd class="data--string">family</dd>
  <dt id="given-name" class="label">g_name</dt>
  <dd class="data--string">given</dd>
<dl>

上のfamilyと言う<dd>の値をラベルf_name経由で取得したい。Capybaraであれば、find("dd.data--string")で取得可能ですが、該当するものが2つあり(更に表示が増える可能性も今後ある)、find_all("dd.data--string").firstとかで順番を指定して取るのも可読性が低いと思うので、f_nameラベルの隣の要素として取得できないかと思いました。

解決

find("dt#family-name", text: "f_name").find("+dd").text # =>"family"
find("dt#family-name", text: "f_name").first(:xpath, './following-sibling::dd').text # => "family"

上のどちらでも希望通りの値が取得可能です。
余談ですが、こちらで紹介した、CapybaraJavaScriptのテスト時では前者の+を用いた手法はエラーになって使えないので注意。

sibling()

siblingと言うメソッドも用意されていて、find("dt#family-name", text: "f_name").sibling("dd")といった形で使います。しかし、このメソッドはfind()見つけた要素と横並びになっている(兄弟?)タグを探索します。ですので、今書いたコードを最初のhtmlに使用すると、ddが2つ見つかってしまいエラーになるので注意。(find()の仕様と同じ。詳しくはリファレンスで)

参考

stackoverflow.com

www.rubydoc.info