カピバラのあいまいさを解決するにはどうすればよいですか?何らかの理由でページ内に同じ値のリンクが必要ですが、エラーが発生するためテストを作成できません
Failure/Error: click_link("#tag1")
Capybara::Ambiguous:
Ambiguous match, found 2 elements matching link "#tag1"
これを避けられない理由は、設計のためです。ツイート/タグを右側に、タグをページの左側に配置して、Twitterページを再作成しようとしています。したがって、同一のリンクページが同じページに表示されることは避けられません。
私の解決策は
first(:link, link).click
の代わりに
click_link(link)
カピバラのこのような動作は意図的なものであり、他のほとんどの回答で示唆されているように修正すべきではないと考えています。
2.0より前のバージョンのCapybaraは、例外を発生させる代わりに最初の要素を返しましたが、後でCapybaraのメンテナーはそれは悪い考えであり、それを上げる方が良いと判断しました。多くの場合、最初の要素を返すことは、開発者が返すことを望んでいた要素ではなく、返すことにつながることが決定されました。
ここで最も支持された答えは、first
の代わりにall
またはfind
を使用することをお勧めしますが、
all
とfirst
は、そのようなロケーターを持つ要素がページに表示されるまで待機しませんが、find
は待機しますall(...).first
およびfirst
は、将来そのようなロケーターを持つ別の要素がページに表示される可能性がある状況からユーザーを保護しません。その結果、誤った要素を見つける可能性があります他の曖昧さの少ないロケーターを選択することをお勧めします :たとえば、ID、クラス、または他のcss/xpathロケーターで要素を選択し、1つの要素のみがそれに一致するようにします。
ここでのメモとして、あいまいさを解決する際に私が通常役立つと考えるいくつかのロケーターがあります。
find('ul > li:first-child')
最初のli
がページに表示されるまで待機するため、first('ul > li')
よりも便利です。
click_link('Create Account', match: :first)
少なくとも1つの[アカウントの作成]リンクがページに表示されるまで待機するため、first(:link, 'Create Account').click
よりも優れています。ただし、ページに2回表示されない一意のロケーターを選択することをお勧めします。
fill_in('Password', with: 'secret', exact: true)
exact: true
は、Capybaraに完全に一致するもののみを検索するよう指示します。つまり、「パスワード確認」は検索しません。
上記のソリューションはうまく機能しますが、好奇心those盛な人には次の構文も使用できます。
click_link(link_name, match: :first)
詳細についてはこちらをご覧ください。
新しい回答:
あなたは次のようなものを試すことができます
_all('a').select {|elt| elt.text == "#tag1" }.first.click
_
利用可能なカピバラ構文をよりよく利用するこれを行う方法があるかもしれません-all("a[text='#tag1']").first.click
の行に沿って何かが、手元に正しい構文を考えることができず、私は見つけることができません適切なドキュメント。つまり、同じid
、class
、およびテキストを含む2つの_<a>
_タグを使用することから始めると、少し奇妙な状況になります。 find
within
をDOMの適切なセグメントにすることができるので、それらが異なるdivの子である可能性はありますか。 (HTMLソースの一部を確認すると役立ちます)。
古い回答:(「#tag1」とは、要素に「tag1」のid
があることを意味すると考えた)
どのリンクをクリックしますか?最初の場合(または問題ではない場合)、次のことができます。
_find('#tag1').click
_
そうでなければあなたはできる
_all('#tag1')[1].click
_
2番目をクリックします。
match
を使用して、最初のものを確実に見つけることができます。
_find('.selector', match: :first).click
_
しかし、重要なことは、おそらくこれを行いたくないでしょう、これは脆性テストにつながるので、重複出力コードの匂いを無視しているためです- 誤検知一致する要素の1つを削除しましたが、テストはもう一方の要素を喜んで見つけたため、失敗するはずだったときに機能し続けます。
より良い方法はwithin
を使用することです:
_within('#sidebar') do
find('.selector).click
end
_
これにより、Capybaraの自動待機および自動再試行機能(find('.selector').click
を使用すると失われます)を活用しながら、検索する要素を確実に見つけることができ、より明確になります。意図は何ですか。
ここで既存の知識を追加するには:
JSテストの場合、Capybaraは2つのスレッド(RSpec用、Rails用)と2番目のプロセス(ブラウザー)の同期を維持する必要があります。これは、ほとんどのマッチャーおよびノード検索メソッドで(構成された最大待機時間まで)待機することでこれを行います。
Capybaraには、主に_Node#all
_という待機しないメソッドもあります。それらを使用することは、断続的に失敗することをスペックに伝えるようなものです。
受け入れられた答えは、page.first('selector')
を示唆しています。 _Node#first
_は_Node#all
_ を使用するため、これは少なくともJS仕様では望ましくありません。
とはいえ、Node#first
_willCapybaraを次のように設定する場合、待機します:
_# Rails_helper.rb
Capybara.wait_on_first_by_default = true
_
このオプションは Capybara 2.5.0で追加 で、デフォルトではfalseです。
アンドレイが述べたように、代わりに使用する必要があります
_find('selector', match: :first)
_
または、セレクタを変更します。どちらも構成またはドライバーに関係なく機能します。
さらに複雑なことに、古いバージョンのCapybara(または構成オプションを有効にした場合)では、_#find
_はあいまいさを喜んで無視し、最初に一致したセレクターを返すだけです。これは、仕様の明示性を低下させるため、あまり良くありません。これがデフォルトの動作ではなくなった理由だと思います。詳細については既に説明したため、省略します。
その他のリソース:
この投稿 のため、「match」オプションで修正できます:
Capybara.configure do |config|
config.match = :prefer_exact
end
キュウリのあいまいなエラーを回避するため。
解決策1
first("#tag1").click
解決策2
Cucumber features/filename.feature --guess