web-dev-qa-db-ja.com

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

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

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

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

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

はい、含む記述ブロックに:js => trueを設定します:)

どんなアイデアでも大歓迎です!ここに意図的な遅延を入れる必要がないことを望んでいます。

78
Kevin Davis

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

ここでは、可視要素が表示されるまでCapybaraが待機するようにします。これは、visibleオプションを指定することで実現できます。

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

試したことはありませんが、findが常に表示される要素を待機するようにしたい場合は、ignore_hidden_elements構成オプションも役立ちます。

125
Jon M

これは私にとって完璧に機能する別の方法です:

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

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

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

要素が隠されていると断言します。

35

要素がページ上にあるが表示されていないことを確認する場合は、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)
20
Zubin

を使用して:

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

Railsアプリケーションがあります。このアプリケーションには、クリックするとAJAXリクエストを送信して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();

通知を送信し、Cucumber(cucumber-Rails gem with Capybara support)を使用して通知ステータスメッセージをユーザーに表示するシナリオをテストしていました

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 asserting a elements of elements これは、要素の属性を生の方法で検査する方法を示しました。

また、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 assert element of attributes of element

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

 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')
9
Jignesh Gohel

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

この失敗は、目に見えていると考えられているもの、またはドライバーの移植性がなく、文書化されていないものと見なされるものの誤解から生じる場合があります。いくつかのテスト:

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

Poltergeistも同様の動作をしますが、内部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

Seleniumの動作はまったく異なります。空の要素を非表示にし、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でした(both可視および不可視要素を参照)、
  • 現在はtrueです
  • Capybara.ignore_hidden_elementsオプションによって制御されます。

参照

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

this post をご覧ください。これは、すべてのajaxリクエストが完了するまで待機するためのサンプルメソッドを提供します。

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

'should'は非推奨の構文であるため、受け入れられた答えは少し時代遅れです。最近では、expect(page).not_to have_css('#blah', visible: :hidden)の行に沿って何かをする方が良いでしょう。

2
Alex Foxleigh

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

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

基本的に、表示されるべきものを探すためにカピバラのデフォルトの待機時間を使用し、存在しない場合はクリックを再試行します。

繰り返しますが、should have_selectorメソッドを最初に試す必要がありますが、うまくいかない場合はこれを試してください

1
Dono