2012-09-23 19 views
12

Tengo una prueba de integración de Rails que está fallando, y no puedo entender por qué. Estoy usando Capybara con Selenium como el controlador.Prueba de integración de Capybara con JavaScript asíncrono

La prueba comprueba que el contenido de la página ha sido eliminado después de que se lleva a cabo una llamada AJAX. La acción relevante es que se haga clic en un botón y que al hacer clic en el botón se elimine una sección de la página mediante una llamada jQuery remove(). Aquí está una aproximación del código de las pruebas de integración:

click_button("Remove stuff") 
assert has_no_link?("This should be removed") 

La aserción falla, lo que implica que todavía existe el enlace.

He estado leyendo sobre Capybara, y sé que puede ampliar el tiempo de espera predeterminado. Lo extendí a un valor ridículo (20 segundos) y aún así la afirmación falla.

Cuando sigo el proceso de prueba a mí mismo de forma manual, la fuente de la página sigue mostrando el contenido, pero el DOM no lo hace (mediante la visualización de DOM Inspector de Firefox y buscar el elemento). ¿Es este el problema? Incluso he intentado inspeccionar el DOM mientras que las pruebas se están ejecutando en Firefox para comprobar si el contenido estaba allí, y no parece ser así.

No tengo idea de cómo Capybara aún encuentra este enlace que ya no existe en el DOM. ¿Está Capibara examinando la fuente en lugar del DOM y buscando el enlace allí? Si es así, no tengo idea de cómo corregir esta prueba para asegurarme de que la prueba pase. Actualizar la página solucionaría el problema, pero eso no es exactamente lo que un usuario haría, por lo que dudo en cambiar la página solo para que la prueba pase ...

Me encantaría cualquier recomendación sobre cómo abordar este problema.

Gracias!

+1

¿Finalmente encontró una solución a su problema? Tengo uno similar y me pregunto si puede ayudarme. –

+1

No, desafortunadamente no. Pasé demasiado para que esa única prueba funcione, así que terminé comentando en lugar de solucionarlo. Lo siento, no puedo ser de más ayuda ... ¡No tenía la energía para profundizar después de pasar tanto tiempo! ¡Siéntete libre de contestar la pregunta si la resuelves y estaré feliz de darte crédito! – aardvarkk

+0

¿Recordó incluir 'js: true' en su rspec? – RubeOnRails

Respuesta

0

Hay una forma clara de verificar que las solicitudes de AJAX estén hechas, lo que aprendí de this article. En lugar de wait con un tiempo específico, puede usar la función ajax $.active (que es not in the actual API but is exposed para que pueda usarla). $.active indica el número de conexiones activas a un servidor, por lo que cuando llega a cero se conoce la petición AJAX se hace:

wait_until do 
    page.evaluate_script('$.active') == 0 
end 

Si eso no funciona, entonces el problema está en otra parte (que a juzgar por lo que escribiste parece probable). Si el cambio solo ocurre en el DOM, debe asegurarse de que javascript esté habilitado para su prueba/especificación. En rspec, por ejemplo, establece :js => true para hacer eso; en Pepino agrega una línea arriba del escenario con @javascript. No uso las pruebas predeterminadas de los rieles, pero debe haber una configuración para hacer lo mismo.

+0

Hmm ... Estoy usando el controlador Selenium en Capybara, que de forma predeterminada parece ser compatible con las pruebas de JavaScript (consulte https://github.com/jnicklas/capybara#drivers). Traté de agregar tu código de espera, pero eso no lo solucionó. ¡Buenas ideas! Todavía no resuelto ... – aardvarkk

+0

¿Utiliza el carpincho para cualquier otra prueba que implique javascript? –

+0

Sí, pero este es el único que está buscando información * eliminada *. Todas las demás cosas parecen funcionar ... Por ejemplo, verificar que las consultas AJAX den como resultado nuevos botones o contenido modificado. Pero algo sobre jQuery 'remove()' no parece estar bien. Si examino 'page.html', aún muestra el contenido allí, por lo que definitivamente algo va mal aquí. – aardvarkk

0

¿está la primera prueba algo más con el enlace, y luego las pruebas que se retira?

En otras palabras, es la prueba de algo como:

has_no_link = $('#id_for_link') 
//.... some test 
click_button("Remove stuff") 
assert has_no_link?("This should be removed") 

Si ese es el caso, entonces has_no_link todavía apuntará al enlace. remove() lo eliminará del DOM, pero su variable aún lo señala en la memoria.

Debe consultar nuevamente el enlace en el DOM para ver si obtiene un resultado.

0

Tuve que volver a escribir wait_until para una prueba que implicaba esperar a una devolución de llamada desencadenada por la transmisión de un video de youtube hasta cierto punto. Esto es lo que he usado:

# in spec_helper.rb 
require "timeout" 
def wait_until time=0.1 
    Timeout.timeout(Capybara.default_wait_time) do 
     sleep(time) until value = yield 
     value 
    end 
end 
+1

Para versiones más recientes de Capybara, tenga en cuenta que 'default_wait_time' ha quedado en desuso. Use 'default_max_wait_time' ahora. – Sia

0

par de enfoques pensé en:

1: Comprobación de la versión capibara y buscar los errores con su versión

2: Tal vez trate de hacer un hallazgo en el enlace después de que el botón se hace clic en

click_button ("quitar cosas") hallazgo. (: XPath, '// a [texto() =' enlace debe retirarse ') debe be_false

3: ¿Usar has_link? en lugar de has_no_link?

click_button ("quitar cosas") page.has_link? ("Enlace debe ser eliminado"). Be_false debe

0

Siempre se puede hacer esto manualmente. El uso de la idea de @ Shioyama:

def wait_for_ajax 
    timer_end = Time.now + 5.seconds 
    while page.evaluate_script('$.active') != 0  
     if Time.now > timer_end 
     fail "Page took more than 5 seconds to load via ajax" 
     end 
     sleep 0.1 
    end 
    end 
3

Thoughtbot tiene una gran entrada de blog en espera de AJAX, que se puede leer here, a pesar de que se basa en Rspec, y parece que está utilizando TestUnit.

Funciona muy bien para situaciones en las que el carpincho no espera lo suficiente, pero no agrega tiempos de espera innecesariamente largos. Yo trabajo sobre todo en Rspec ahora, pero creo que se puede modificar al hacer esto:

# Create this file in test/support/wait_for_ajax.rb 
module WaitForAjax 
    def wait_for_ajax 
    Timeout.timeout(Capybara.default_max_wait_time) do 
     loop until finished_all_ajax_requests? 
    end 
    end 

    def finished_all_ajax_requests? 
    page.evaluate_script('jQuery.active').zero? 
    end 
end 

Puede incluir cuando sea necesario en el archivo de prueba individual, o utilizar una de las estrategias previstas en this SO post para incluir de forma automática todo el tiempo

Luego, cada vez que tenga una prueba que no está esperando adecuadamente que AJAX termine, simplemente inserte la línea wait_for_ajax. Usando su código como ejemplo:

click_button("Remove stuff") 
wait_for_ajax 
assert has_no_link?("This should be removed") 
Cuestiones relacionadas