ruby - rails - ¿Cómo hacer que Capibara controle la visibilidad después de que se haya ejecutado algo de JS?
slim programming language (8)
Después de cargar una página, tengo un código que se ejecuta y oculta y muestra varios elementos en función de los datos devueltos por un xhr.
Mi prueba de integración se ve así:
it "should not show the blah" do
page.find(''#blah'').visible?.should be_true
end
Cuando voy manualmente a la página en el contexto en que se ejecuta esta prueba, #blah no está visible como esperaba. Sospecho que Capybara está mirando el estado inicial de la página (invisible en este caso), evaluando el estado del DOM y fallando la prueba antes de que se ejecute el JS.
Sí, configuré :js => true
en el bloque de descripción que contiene :)
¡Cualquier idea sería muy apreciada! Espero no tener que poner un retraso intencional aquí, eso se siente escamoso y ralentizará las cosas.
Creo que la declaración de find
aquí es la que tiene la espera implícita, por lo que Capibara esperará hasta que el elemento esté en la página, pero no esperará a que se vuelva visible.
Aquí, querrá que Capybara espere a que aparezca el elemento visible, lo que debería ser posible al especificar la opción visible
:
expect(page).to have_selector(''#blah'', visible: true)
No lo he intentado, pero la opción de configuración ignore_hidden_elements
podría ser útil aquí, si desea que siempre espere elementos visibles.
Es posible que desee consultar esta publicación , que proporciona un método de muestra para esperar hasta que se completen todas las solicitudes de Ajax:
def wait_for_ajax(timeout = Capybara.default_wait_time)
page.wait_until(timeout) do
page.evaluate_script ''jQuery.active == 0''
end
end
Esta es otra forma de hacerlo que funciona perfectamente bien para mí:
find(:css, "#some_element").should be_visible
Especialmente para hallazgos más complejos, como
find(:css, "#comment_stream_list li[data-id=''#{@id3}'']").should_not be_visible
que afirmaría que un elemento ha sido ocultado.
La respuesta aceptada está un poco desactualizada ahora ya que ''should'' es sintaxis obsoleta. En estos días, sería mejor que hicieras algo en la línea de expect(page).not_to have_css(''#blah'', visible: :hidden)
Las otras respuestas aquí son la mejor manera de "esperar" el elemento. Sin embargo, he encontrado que esto no funcionó para el sitio en el que estoy trabajando. Básicamente, el elemento que necesitaba hacer clic era visible antes de que la función detrás de eso estuviera completamente cargada. Esto es en fracciones de segundo, pero encontré que mi prueba se ejecutó tan rápido en alguna ocasión que hizo clic en el botón y no pasó nada. Logré solucionarlo haciendo esta expresión booleana 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
Básicamente, utiliza el tiempo de espera predeterminado de capibara para buscar algo que debería aparecer, si no está allí, volverá a intentar el clic.
Una vez más, diré que el método should have_selector
debe probarse primero, pero si no funciona, intente esto.
Si desea comprobar que un elemento está en la página pero no está visible, visible: false
no funcionará como podría esperar. Me dejó perplejo por un momento.
He aquí cómo hacerlo:
# 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)
Utilizando:
Ruby: ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
Rails: 3.2.9
Capybara: 2.0.3
Tengo una aplicación Rails en la que hay un enlace que, al hacer clic, debe enviar una solicitud posterior a AJAX y devolver una respuesta JS.
Código de enlace:
link_to("Send Notification", notification_path(user_id: user_id), remote: true, method: :post)
La respuesta JS (archivo .js.haml) debe alternar el siguiente div oculto en la página donde existe el enlace:
#notification_status(style=''display:none'')
Contenido del archivo js.haml:
:plain
var notificationStatusContainer = $(''#notification_status'');
notificationStatusContainer.val("#{@notification_status_msg}");
notificationStatusContainer.show();
Estaba probando mi escenario de envío de notificaciones y mostrando el mensaje de estado de notificación al usuario usando Pepino ( gema de pepino-riel con soporte de Capibara incorporado )
Estaba tratando de probar que el elemento que tiene id: notification_status era visible en la respuesta exitosa en mi definición de paso. Para esto probé las siguientes declaraciones:
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)
Ninguno de los anteriores funcionó para mí y falló en mi paso. De los 5 fragmentos mencionados anteriormente los 4 últimos fallaron con el siguiente error:
''expected to find css "#notification_status" but there were no matches. Also found "", which matched the selector but not all filters. (Capybara::ExpectationNotMet)''
lo cual era extraño porque la siguiente declaración estaba pasando correctamente:
page.has_selector?(''#notification_status'')
Y, de hecho, inspeccioné la fuente de la página usando
print page.html
que apareció
<div style='''' id=''notification_status''></div>
que se esperaba
Finalmente, encontré que este enlace capibara afirma los atributos de un elemento que mostraba cómo inspeccionar el atributo de un elemento de manera cruda.
También encontré en la documentación de Capybara para visible? método ( http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#visible%3F-instance_method ) a continuación la información:
Not all drivers support CSS, so the result may be inaccurate.
Por lo tanto, llegué a la conclusión de que al probar la visibilidad de un elemento no confío en los resultados de Capibara visible? método al usar un selector de CSS y el uso de la solución sugerida en el enlace capibara afirmar atributos de un elemento
Se me ocurrió lo siguiente:
module CustomMatchers
def should_be_visible(css_selector)
find(css_selector)[''style''].should_not include(''display:none'', ''display: none'')
end
end
World(CustomMatchers)
Uso:
should_be_visible(''#notification_status'')
Qué medios visibles no son obvios
La falla puede provenir de un malentendido de lo que se considera visible o no, ya que no es obvio, no es portátil y no está documentado. Algunas pruebas:
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>
Lo único que la prueba de Rack considera invisible es la display: none
línea display: none
(no CSS interno ya que no hace selectores):
!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 tiene un comportamiento similar, pero puede tratar con CSS interno y la manipulación de 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
El selenio se comporta de manera bastante diferente: si considera que un elemento vacío es invisible y está visibility-hidden
, además de 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
Otra captura común es el valor predeterminado de visible
:
- solía ser
false
(ve elementos visibles e invisibles), - actualmente es
true
- está controlado por la opción
Capybara.ignore_hidden_elements
.
Prueba ejecutable completa en mi GitHub .