web-dev-qa-db-ja.com

カピバラのあいまいさの解決

カピバラのあいまいさを解決するにはどうすればよいですか?何らかの理由でページ内に同じ値のリンクが必要ですが、エラーが発生するためテストを作成できません

Failure/Error: click_link("#tag1")
     Capybara::Ambiguous:
       Ambiguous match, found 2 elements matching link "#tag1"

これを避けられない理由は、設計のためです。ツイート/タグを右側に、タグをページの左側に配置して、Twitterページを再作成しようとしています。したがって、同一のリンクページが同じページに表示されることは避けられません。

93
neilmarion

私の解決策は

first(:link, link).click

の代わりに

click_link(link)
140
e-zinc

カピバラのこのような動作は意図的なものであり、他のほとんどの回答で示唆されているように修正すべきではないと考えています。

2.0より前のバージョンのCapybaraは、例外を発生させる代わりに最初の要素を返しましたが、後でCapybaraのメンテナーはそれは悪い考えであり、それを上げる方が良いと判断しました。多くの場合、最初の要素を返すことは、開発者が返すことを望んでいた要素ではなく、返すことにつながることが決定されました。

ここで最も支持された答えは、firstの代わりにallまたはfindを使用することをお勧めしますが、

  1. allfirstは、そのようなロケーターを持つ要素がページに表示されるまで待機しませんが、findは待機します
  2. 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に完全に一致するもののみを検索するよう指示します。つまり、「パスワード確認」は検索しません。

72
Andrei Botalov

上記のソリューションはうまく機能しますが、好奇心those盛な人には次の構文も使用できます。

click_link(link_name, match: :first)

詳細についてはこちらをご覧ください。

http://taimoorchangaizpucitian.wordpress.com/2013/09/06/capybara-click-link-different-cases-and-solutions/

25
Greg L

新しい回答:

あなたは次のようなものを試すことができます

_all('a').select {|elt| elt.text == "#tag1" }.first.click
_

利用可能なカピバラ構文をよりよく利用するこれを行う方法があるかもしれません-all("a[text='#tag1']").first.clickの行に沿って何かが、手元に正しい構文を考えることができず、私は見つけることができません適切なドキュメント。つまり、同じidclass、およびテキストを含む2つの_<a>_タグを使用することから始めると、少し奇妙な状況になります。 findwithinをDOMの適切なセグメントにすることができるので、それらが異なるdivの子である可能性はありますか。 (HTMLソースの一部を確認すると役立ちます)。


古い回答:(「#tag1」とは、要素に「tag1」のidがあることを意味すると考えた)

どのリンクをクリックしますか?最初の場合(または問題ではない場合)、次のことができます。

_find('#tag1').click
_

そうでなければあなたはできる

_all('#tag1')[1].click
_

2番目をクリックします。

23

matchを使用して、最初のものを確実に見つけることができます。

_find('.selector', match: :first).click
_

しかし、重要なことは、おそらくこれを行いたくないでしょう、これは脆性テストにつながるので、重複出力コードの匂いを無視しているためです- 誤検知一致する要素の1つを削除しましたが、テストはもう一方の要素を喜んで見つけたため、失敗するはずだったときに機能し続けます。

より良い方法はwithinを使用することです:

_within('#sidebar') do
  find('.selector).click
end
_

これにより、Capybaraの自動待機および自動再試行機能(find('.selector').clickを使用すると失われます)を活用しながら、検索する要素を確実に見つけることができ、より明確になります。意図は何ですか。

9
TALlama

ここで既存の知識を追加するには:

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_はあいまいさを喜んで無視し、最初に一致したセレクターを返すだけです。これは、仕様の明示性を低下させるため、あまり良くありません。これがデフォルトの動作ではなくなった理由だと思います。詳細については既に説明したため、省略します。

その他のリソース:

6
johncip

この投稿 のため、「match」オプションで修正できます:

Capybara.configure do |config|
  config.match = :prefer_exact
end
5
Skydan

キュウリのあいまいなエラーを回避するため。

解決策1

first("#tag1").click

解決策2

Cucumber features/filename.feature --guess
0
Aravin