一部のJSが実行された後、Capybaraに可視性をチェックさせる方法は?


82

ページをロードした後、xhrによって返されたデータに基づいてさまざまなアイテムを実行および非表示および表示するコードがあります。

私の統合テストは次のようになります。

it "should not show the blah" do
    page.find('#blah').visible?.should be_true
end 

このテストが実行されるコンテキストで手動でページに移動すると、期待どおりに#blahが表示されません。Capybaraがページの初期状態(この場合は非表示)を調べて、DOMの状態を評価し、JSが実行される前にテストに失敗しているのではないかと思います。

はい、:js => true含まれているdescribeブロックにを設定しました:)

どんなアイデアでも大歓迎です!ここに意図的な遅延を入れる必要がないことを願っています。それは不安定に感じ、物事を遅くします。


1
ドライバーは何ですか?XHRが終了した後に期待されるHTMLは何ですか?
CiroSantilli郝海东冠事病六四事件法轮功2014年

回答:


132

findここでのステートメントは暗黙的な待機を伴うものだと思うので、Capybaraは要素がページに表示されるまで待機しますが、要素が表示されるのを待ちません。

ここでは、表示される要素が表示されるのをCapybaraで待機する必要がありvisibleます。これは、次のオプションを指定することで実現できます。

expect(page).to have_selector('#blah', visible: true)

私は試していませんが、表示されている要素を常に待ちignore_hidden_elementsたい場合は、ここでも構成オプションが役立つ可能性がありますfind


6
誰かが最初に@Kevinのメモを見逃した場合(私のように)、js:trueこれが機能するためには、包含ブロックにある必要があります。
クリスベック

3
これはすごいです。それは私が到達するのを助けました:expect(page).to have_selector('#flash-message', visible: false, text: "Signed in Successfully")-この答えを投稿してくれてありがとう
チャックバージェロン2015年

jqueryスライドダウン要素の可視性をテストするとき、visibleオプションは私には効果がありませんでした。私はexpect(find( '#blah')。visible?)。tobe_falseyを使用する必要がありました。
trueinViso 2016年

is_visibleのようなものが欲しいですか?次に、それ以外のことを行います
user1735921 2016

37

これは私にとって完全にうまく機能する別の方法です:

find(:css, "#some_element").should be_visible

特に、次のようなより複雑な検索の場合

find(:css, "#comment_stream_list li[data-id='#{@id3}']").should_not be_visible

これは、要素が非表示になっていることを表明します。


1
should_not be_visibleカピバラの実行として私に良い見ていないwait_until { base.visible? }とき、素子#見えますか?呼び出されています。
フオングエン

1
@ phng-nguyn、#wait_untilは最近のバージョンのCapybaraから削除されました。
solidcell 2013

3
これは実際には「page.shouldhave_selector ...」よりも優れたバリアントです。これは、テキストが失敗した場合、要素が実際には明示的に非表示であると言われるのに対し、前述のバリアントは「一致するものがなかった」というエラーを引き起こすだけだからです。 、それは少しイライラします。
インストーラー

これは、受け入れられているソリューションと同じではありません。このコードの場合、Capybaraは要素がDOMに含まれるまで待機し、すぐに可視性を確認します。可視性が変化することを期待している場合、これはスペックに競合状態を追加する可能性があります。
johncip 2016

1
.should_not be_visibleカバーdisplay: noneがjQueryによって設定されているかどうか誰かが知っていますか?それは私にはうまくいかないようです。
Antrikshy 2017年

20

要素がページ上にあるが表示されていないことを確認したい場合は、visible: false期待どおりに機能しません。私は少し困惑していました。

方法は次のとおりです。

# assert element is present, regardless of visibility
page.should have_css('#some_element', :visible => false)
# assert visible element is not present
page.should have_no_css('#some_element', :visible => true)

1
あなたは使用することはできませんshould_notので、Ajaxを、カピバラと
マルク=アンドレ・Lafortune

@Marc-AndréLafortune、capybaraでajaxをテストするには、Capybara.javascript_driverを使用します。
ズビン2013

1
javascript_driveを使用have_cssすると、要素が見つかることを期待しているため、タイムアウト期間全体を待ってからあきらめます。たとえば、のshould have_no_content代わりにを使用する必要がありshould_not have_contentます。
マルク=アンドレ・Lafortune

1
expect(page).not_to have_selector("#some_element", visible: true)javascript_driverタイムアウト期間全体を待たずに、を使用して問題なく動作しました。
Jason Swett 2015年

1
実際、私のコメント以来、これは変更されておりshould_not、今すぐ使用できます(そして使用する必要があります)。ごめんなさい!
マークアンドレラフォーチュン2015

9

使用:

 Ruby:     ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
 Rails:    3.2.9
 Capybara: 2.0.3

Railsアプリケーションがあり、クリックするとAJAX POSTリクエストを送信し、JSレスポンスを返すリンクがあります。

リンクコード:

 link_to("Send Notification", notification_path(user_id: user_id), remote: true, method: :post)

JS応答(.js.hamlファイル)は、リンクが存在するページで次の非表示のdivを切り替える必要があります。

 #notification_status(style='display:none')

js.hamlファイルの内容:

:plain
  var notificationStatusContainer = $('#notification_status');
  notificationStatusContainer.val("#{@notification_status_msg}");
  notificationStatusContainer.show();

私は通知を送信し、キュウリを用いてユーザに通知ステータスメッセージを表示する私のシナリオをテストしていた(カピバラのサポートが組み込まれて宝石をキュウリ、レール

ステップ定義の成功した応答でid:notification_statusを持つ要素が表示されることをテストしようとしました。このために、次のステートメントを試しました。

page.find('#notification_status').should be_visible
page.should have_selector('#notification_status', visible: true)
page.should have_css('#notification_status', visible: true)
page.find('#notification_status', visible: true)
page.find(:css, 'div#notification_status', visible: true)

上記のどちらも機能せず、ステップに失敗しました。上記の5つのスニペットのうち、最後の4つは次のエラーで失敗しました。

'expected to find css "#notification_status" but there were no matches. Also found "", which matched the selector but not all filters. (Capybara::ExpectationNotMet)'

次のステートメントが正しく渡されていたため、これは奇妙でした。

page.has_selector?('#notification_status')

そして実際、私はを使用してページソースを調べました

  print page.html

現れた

<div style='' id='notification_status'></div>

予想通りでした。

最後に、このリンクcapybaraが要素の属性をアサートしていることを発見しました。これは、要素の属性を生の方法で検査する方法を示しています。

また、Capybaraのドキュメントで目に見えるものを見つけましたか?メソッド(http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#visible%3F-instance_method)次の情報:

 Not all drivers support CSS, so the result may be inaccurate.

したがって、要素の可視性をテストするとき、カピバラの可視性の結果に依存しないという結論に達しましたか?CSSセレクターを使用し、リンクcapybaraで提案されているソリューションを使用する場合のメソッド要素の属性をアサートします

私は次のことを思いついた:

 module CustomMatchers
   def should_be_visible(css_selector)
    find(css_selector)['style'].should_not include('display:none', 'display: none')
   end
 end

 World(CustomMatchers)

使用法:

should_be_visible('#notification_status')

8

目に見える意味は明らかではありません

失敗は、それが自明ではなく、ドライバーに移植可能でなく、文書化が不十分であるため、目に見えるかどうかと見なされるものの誤解から生じる可能性があります。いくつかのテスト:

HTML:

<div id="visible-empty"                                                                   ></div>
<div id="visible-empty-background"      style="width:10px; height:10px; background:black;"></div>
<div id="visible-empty-background-same" style="width:10px; height:10px; background:white;"></div>
<div id="visible-visibility-hidden"     style="visibility:hidden;"                        >a</div>
<div id="visible-display-none"          style="display:none;"                             >a</div>

Rackテストが非表示と見なすのはインラインだけですdisplay: none(セレクターを実行しないため、内部CSSではありません)。

!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

ポルターガイストも同様の動作をしますが、内部のCSSとJsのstyle.display操作を処理できます。

Capybara.current_driver = :poltergeist
!all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
!all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

セレンはかなり異なった動作:空の要素が見えないと考える場合visibility-hiddenと同様にdisplay: none

Capybara.current_driver = :selenium
 all('#visible-empty',                 visible: true).empty? or raise
!all('#visible-empty-background',      visible: true).empty? or raise
!all('#visible-empty-background-same', visible: true).empty? or raise
 all('#visible-visibiility-hidden',    visible: true).empty? or raise
 all('#visible-display-none',          visible: true).empty? or raise

もう1つの一般的な問題は、次のデフォルト値ですvisible

  • 以前はfalse(表示要素と非表示要素の両方を参照)、
  • 現在は true
  • Capybara.ignore_hidden_elementsオプションによって制御されます。

参照

私のGitHubで実行可能な完全なテスト。


1
素晴らしい答え-あなたがこれに注いだ努力に感謝します。複数のドライバーを使用してスイート内の要素の可視性をテストすることは簡単ではありません。
Andy Triggs 2015年

1
「以前はfalse(表示要素と非表示要素の両方を参照)でしたが、現在はtrueであり、Capybara.ignore_hidden_​​elementsオプションによって制御されています。」詳細については、このブログ投稿を参照してください:elabs.se/blog/60-introducing-capybara-2-1
rizidoro

5

あなたは見たいかもしれないこの記事のすべてのAjaxリクエストが完了するまで待機するサンプルの方法を提供します:

def wait_for_ajax(timeout = Capybara.default_wait_time)
  page.wait_until(timeout) do
    page.evaluate_script 'jQuery.active == 0'
  end
end

5
Capybara 2から削除さwait_untilため、このソリューションは将来互換性がありません。
parhamr 2013

1
使用Timeout.timeout
Ian Vaughan

より良い使用法Selenium::WebDriver::Wait
Nakilon 2016

セレンのみを使用する場合
Nickolay Kondratenko 2017年

2

'should'は非推奨の構文であるため、受け入れられた回答は少し古くなっています。最近は、次のようなことをしたほうがいいでしょう。expect(page).not_to have_css('#blah', visible: :hidden)


1

ここでの他の答えは、要素を「待つ」ための最良の方法です。しかし、私が取り組んでいるサイトではこれが機能しないことがわかりました。基本的に、クリックが必要な要素は、その背後にある関数が完全に読み込まれる前に表示されていました。これはほんの一瞬ですが、テストが非常に速く実行され、ボタンをクリックしても何も起こらなかったことがわかりました。この間に合わせのブール式を実行することで、なんとか回避できました。

if page.has_selector?('<css-that-appears-after-click>')
  puts ('<Some-message-you-want-printed-in-the-output>')
else
  find('<css-for-the-button-to-click-again>', :match == :first).trigger('click')
end

基本的には、capybaraのデフォルトの待機時間を使用して、表示されるはずの何かを探します。表示されない場合は、クリックを再試行します。

もう一度、このshould have_selector方法を最初に試す必要があると言いますが、うまくいかない場合は、これを試してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.