Après avoir chargé une page, j'ai un code qui s'exécute, qui se cache et affiche divers éléments en fonction des données renvoyées par une xhr.
Mon test d'intégration ressemble à ceci:
it "should not show the blah" do
page.find('#blah').visible?.should be_true
end
Quand je vais manuellement à la page dans le contexte où ce test est exécuté, #blah est not visible comme prévu. Je soupçonne que Capybara examine l'état initial de la page (invisible dans ce cas), évalue l'état du DOM et échoue au test avant l'exécution du JS.
Oui, je règle le :js => true
sur le bloc décrit :)
Toutes les idées seraient grandement appréciées! J'espère ne pas avoir à mettre un délai intentionnel ici, cela semble floconneux et va ralentir les choses.
Je pense que la déclaration find
est celle avec l'attente implicite. Capybara attendra donc que l'élément se trouve sur la page, mais n'attendra pas qu'il soit visible.
Ici, vous voudriez que Capybara attende que l’élément visible apparaisse, ce qui devrait être réalisable en spécifiant l’option visible
:
expect(page).to have_selector('#blah', visible: true)
Je ne l'ai pas essayée, mais l'option de configuration ignore_hidden_elements
Pourrait également être utile si vous vouliez que find
attende toujours les éléments visibles.
C'est une autre façon de le faire qui fonctionne parfaitement pour moi:
find(:css, "#some_element").should be_visible
Surtout pour les découvertes plus complexes, telles que
find(:css, "#comment_stream_list li[data-id='#{@id3}']").should_not be_visible
ce qui affirmerait qu'un élément a été caché.
Si vous voulez vérifier qu'un élément est sur la page mais n'est pas visible, visible: false
_ ne fonctionnera pas comme prévu. M'avait laissé perplexe un peu.
Voici comment le faire:
# 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)
En utilisant:
Ruby: Ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
Rails: 3.2.9
Capybara: 2.0.3
J'ai une application Rails dans laquelle se trouve un lien qui, une fois cliqué, doit soumettre une demande AJAX et envoyer une réponse JS.
Code de lien:
link_to("Send Notification", notification_path(user_id: user_id), remote: true, method: :post)
La réponse JS (fichier .js.haml) doit basculer le div caché suivant sur la page où le lien existe:
#notification_status(style='display:none')
contenu du fichier js.haml:
:plain
var notificationStatusContainer = $('#notification_status');
notificationStatusContainer.val("#{@notification_status_msg}");
notificationStatusContainer.show();
Je testais mon scénario d'envoi de notification et d'affichage du message d'état de notification à l'utilisateur à l'aide de Cucumber ( joyau de concombre-rails avec le support Capybara intégré)
J'essayais de tester que l'élément ayant l'id: notification_status était visible après une réponse positive dans ma définition d'étape. Pour cela, j'ai essayé les instructions suivantes:
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)
Aucune des actions ci-dessus n'a fonctionné pour moi et a échoué. Les cinq derniers extraits énumérés ci-dessus ont échoué avec l'erreur suivante:
'expected to find css "#notification_status" but there were no matches. Also found "", which matched the selector but not all filters. (Capybara::ExpectationNotMet)'
ce qui était étrange parce que la déclaration suivante passait correctement:
page.has_selector?('#notification_status')
Et en fait, j'ai inspecté la source de la page en utilisant
print page.html
qui est apparu
<div style='' id='notification_status'></div>
ce qui était attendu.
Enfin, j'ai trouvé ce lien capybara affirme les attributs d'un élément qui a montré comment inspecter l'attribut d'un élément de manière brute.
Aussi, j'ai trouvé dans la documentation Capybara des éléments visibles? méthode ( http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#visible%3F-instance_method ) informations suivantes:
Not all drivers support CSS, so the result may be inaccurate.
Je suis donc parvenu à la conclusion que lors du test de la visibilité d'un élément, ne vous fiez pas aux résultats de la visibilité de Capybara? méthode en utilisant un sélecteur CSS et en utilisant la solution suggérée dans le lien capybara assert les attributs d'un élément
Je suis venu avec ce qui suit:
module CustomMatchers
def should_be_visible(css_selector)
find(css_selector)['style'].should_not include('display:none', 'display: none')
end
end
World(CustomMatchers)
Usage:
should_be_visible('#notification_status')
Ce que signifie visible n'est pas évident
L'échec peut provenir d'une incompréhension de ce qui est considéré visible ou non, car ce n'est pas évident, il n'est pas portable et il est sous-documenté. Quelques tests:
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>
La seule chose que le test de rack considère comme invisible est inline display: none
_ (pas le CSS interne car il ne fait pas de sélecteurs):
!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 a un comportement similaire, mais il peut gérer les CSS internes et Js style.display
_ manipulation:
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
Sélénium se comporte très différemment: si considère un élément vide invisible et visibility-hidden
aussi bien que 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
Une autre erreur courante est la valeur par défaut de visible
:
false
(voit les deux éléments visibles et invisibles),true
Capybara.ignore_hidden_elements
option.Test complet exécutable sur mon GitHub .
Vous voudrez peut-être regarder this post , qui donne un exemple de méthode pour attendre que toutes les demandes ajax soient terminées:
def wait_for_ajax(timeout = Capybara.default_wait_time)
page.wait_until(timeout) do
page.evaluate_script 'jQuery.active == 0'
end
end
La réponse acceptée est un peu obsolète à présent car "devrait" est une syntaxe déconseillée. De nos jours, vous feriez mieux de faire quelque chose comme expect(page).not_to have_css('#blah', visible: :hidden)
Les autres réponses ici sont la meilleure façon "d'attendre" l'élément. Cependant, j'ai constaté que cela ne fonctionnait pas pour le site sur lequel je travaille. En gros, l'élément sur lequel il fallait cliquer était visible avant que la fonction derrière ne soit entièrement chargée. C’est en quelques fractions de seconde, mais j’ai trouvé que mon test était tellement rapide qu’il a cliqué sur le bouton et qu’il ne s’est rien passé. J'ai réussi à contourner ce problème en faisant cette expression booléenne make-shift:
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
Fondamentalement, il utilise le délai d’attente par défaut de capybara pour rechercher quelque chose qui devrait apparaître. Si ce n’est pas le cas, il réessayera votre clic.
Encore une fois, je dirai que le should have_selector
la méthode devrait être essayée en premier mais si ça ne marche pas, essayez ceci