veces varias una secuencialmente script pagina node funcion evento ejecutar cargar body asincrono javascript python selenium selenium-webdriver protractor

javascript - varias - ejecutar script jquery



Entendiendo ejecutar script asíncrono en Selenium (2)

He estado usando selenium (con enlaces de python y principalmente a través de un protractor ) durante bastante tiempo y cada vez que necesitaba ejecutar un código javascript, he usado el método execute_script() . Por ejemplo, para desplazar la página (python):

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

O, para el desplazamiento infinito dentro de otro elemento (transportador):

var div = element(by.css(''div.table-scroll'')); var lastRow = element(by.css(''table#myid tr:last-of-type'')); browser.executeScript("return arguments[0].offsetTop;", lastRow.getWebElement()).then(function (offset) { browser.executeScript(''arguments[0].scrollTop = arguments[1];'', div.getWebElement(), offset).then(function() { // assertions }); });

O, para obtener un diccionario de todos los atributos de los elementos (python):

driver.execute_script(''var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;'', element)

Pero, la API de WebDriver también tiene execute_async_script() que no he usado personalmente.

¿Qué casos de uso cubre? ¿Cuándo debo usar execute_async_script() lugar del execute_script() regular?

La pregunta es específica al selenio, pero no tiene lenguaje.


¿Cuándo debo usar execute_async_script() lugar del execute_script() regular?

Cuando se trata de verificar las condiciones en el lado del navegador, todas las verificaciones que puede realizar con execute_async_script pueden realizarse con execute_script . Incluso si lo que estás comprobando es asíncrono. Lo sé porque una vez hubo un error con execute_async_script que hizo que mis pruebas fallaran si la secuencia de comandos execute_async_script resultados demasiado rápidos. Por lo que puedo decir, el error ya no existe, por lo que he estado utilizando execute_async_script pero durante meses, usé execute_script para las tareas en las que execute_async_script hubiera sido más natural. Por ejemplo, realizar una verificación que requiere cargar un módulo con RequireJS para realizar la verificación:

driver.execute_script(""" // Reset in case it''s been used already. window.__selenium_test_check = undefined; require(["foo"], function (foo) { window.__selenium_test_check = foo.computeSomething(); }); """) result = driver.wait(lambda driver: driver.execute_script("return window.__selenium_test_check;"))

La llamada require es asíncrona. Sin embargo, el problema con esto, además de filtrar una variable en el espacio global, es que multiplica las solicitudes de red. Cada llamada execute_script es una solicitud de red. El método de wait funciona mediante sondeo: ejecuta la prueba hasta que el valor devuelto sea verdadero. Esto significa una solicitud de red por verificación que realiza la wait (en el código anterior).

Cuando pruebas localmente no es un gran problema. Si tiene que pasar por la red porque tiene los navegadores aprovisionados por un servicio como Sauce Labs (que utilizo, por lo que estoy hablando por experiencia), cada solicitud de red ralentiza su conjunto de pruebas. Por lo tanto, el uso de execute_async_script no solo permite escribir una prueba que parece más natural (llamar a una devolución de llamada, como lo hacemos normalmente con el código asíncrono, en lugar de filtrarse en el espacio global), sino que también ayuda al rendimiento de sus pruebas.

result = driver.execute_async_script(""" var done = arguments[0]; require(["foo"], function (foo) { done(foo.computeSomething()); }); """)

La forma en que lo veo ahora es que si una prueba va a engancharse al código asíncrono en el navegador para obtener un resultado, utilizo execute_async_script . Si va a hacer algo para lo que no hay un método asíncrono disponible, yo uso execute_script .


Aquí está la reference a las dos API (bueno, es Javadoc, pero las funciones son las mismas), y aquí hay un extracto que destaca la diferencia.

[executeAsyncScript] Ejecuta una parte asíncrona de JavaScript en el contexto del marco o ventana seleccionado actualmente. A diferencia de la ejecución de JavaScript síncrono, los scripts ejecutados con este método deben indicar explícitamente que han finalizado invocando la devolución de llamada proporcionada. Esta devolución de llamada siempre se inyecta en la función ejecutada como último argumento.

Básicamente, execSync bloquea las acciones adicionales que realiza el navegador de Selenium, mientras que execAsync no bloquea y llama a una callback cuando se realiza.

Como has trabajado con el transportador, usaré eso como ejemplo. El transportador utiliza executeAsyncScript en get y waitForAngular

En waitForAngular , el transportador debe esperar hasta que angular anuncie que todos los eventos se resolvieron. No puede usar executeScript porque eso necesita devolver un valor al final (aunque supongo que puede implementar un bucle de ocupado que sondea de forma constante hasta que esté listo). La forma en que funciona es que el transportador proporciona una devolución de llamada, que Angular llama una vez que todos los eventos se resuelven, y eso requiere execute AsyncScript. Código here

En get , el transportador debe sondear la página hasta que window.angular establezca el window.angular global. Una forma de hacerlo es driver.wait(function() {driver.executeScript(''return window.angular'')}, 5000) , pero de ese modo, el transportador driver.wait(function() {driver.executeScript(''return window.angular'')}, 5000) el navegador cada pocos ms. En su lugar, hacemos esto (simplificado):

functions.testForAngular = function(attempts, callback) { var check = function(n) { if (window.angular) { callback(''good''); } else if (n < 1) { callback(''timedout''); } else { setTimeout(function() {check(n - 1);}, 1000); } }; check(attempts); };

Nuevamente, eso requiere executeAsyncScript porque no tenemos un valor de retorno inmediatamente. Código here

En total, use executeAsyncScript cuando te importa un valor de retorno en un script de llamada, pero ese valor de retorno no estará disponible de inmediato. Esto es especialmente necesario si no puede sondear el resultado, pero debe obtener el resultado mediante una devolución de llamada o promesa (que usted mismo debe traducir a devolución de llamada).