了解Selenium中的执行异步脚本

时间:2015-01-20 23:52:53

标签: javascript python selenium selenium-webdriver protractor

我一直在使用selenium(主要是python bindingsprotractor)很长一段时间,每次我需要执行javascript代码时,我都使用{ {1}}方法。例如,for scrolling the page(python):

execute_script()

或者,对于infinite scrolling inside an another element(量角器):

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

或者,获得dictionary of all element attributes(python):

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

    });
});

但是,WebDriver API也有execute_async_script(),我没有亲自使用过。

它包含哪些用例?我应该何时使用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) 代替常规execute_async_script()

问题是硒特异性,但与语言无关。

2 个答案:

答案 0 :(得分:23)

  

我应该何时使用execute_async_script()代替常规execute_script()

在浏览器端检查条件时,可以使用execute_async_script执行execute_script可以执行的所有检查。即使您正在检查的内容是异步的。我知道因为曾经有一个execute_async_script的错误导致我的测试失败,如果脚本返回的结果太快了。据我所知,这个错误现在已经消失,所以我一直在使用execute_async_script,但事先数月,我使用execute_script执行execute_async_script本来更自然的任务。例如,执行需要加载带有RequireJS的模块的检查来执行检查:

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;"))

require调用是异步的。然而,除了将变量泄漏到全局空间之外,问题在于它将网络请求倍增。每个execute_script呼叫都是网络请求。 wait方法通过轮询工作:它运行测试直到返回值为true。这意味着wait执行的每次检查都有一个网络请求(在上面的代码中)。

当你在本地测试时,这不是什么大问题。如果你必须通过网络,因为你正在使用像Sauce Labs这样的服务提供的浏览器(我使用它,所以我从经验谈起),每个网络请求都会降低你的测试套件的速度。 因此使用execute_async_script不仅允许编写看起来更自然的测试(调用回调,就像通常使用异步代码一样,而不是泄漏到全局空间中),但它也有助于测试的性能

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

我现在看到的方式是,如果测试要挂钩到浏览器端的异步代码以获得结果,我使用execute_async_script。如果要做的事情没有可用的异步方法,我使用execute_script

答案 1 :(得分:16)

这里是两个API的reference(好吧它的Javadoc,但功能是相同的),这里有一个突出显示差异的摘录< / p>

  

[executeAsyncScript]执行一个异步的JavaScript   当前所选框架或窗口的上下文。不像   执行同步JavaScript,使用此方法执行的脚本   必须通过调用提供的方式明确表示它们已完成   打回来。此回调始终注入已执行的函数   作为最后一个论点。

基本上,execSync阻止了由selenium浏览器执行的进一步操作,而execAsync在callback完成后不会阻塞和调用executeAsyncScript


由于您使用过量角器,我会以此为例。 量角器在getwaitForAngular

中使用waitForAngular

executeScript中,量角器需要等到角度宣布所有事件都已解决。你不能使用get,因为它需要在最后返回一个值(虽然我猜你可以实现一个繁忙的循环,不断轮询角度,直到它完成)。它的工作方式是量角器提供一个回调,Angular会在所有事件都解决后调用,并且需要executeAsyncScript。代码here

window.angular中,量角器需要轮询页面,直到Angular设置全局driver.wait(function() {driver.executeScript('return window.angular')}, 5000)为止。一种方法是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); }; ,但是这样,量角器每隔几毫秒就会在浏览器上敲击。相反,我们这样做(简化):

executeAsyncScript

同样,这需要executeAsyncScript因为我们没有立即返回值。代码here


总而言之,当您关心调用脚本中的返回值时,请使用{{1}},但该返回值不会立即可用。如果您不能轮询结果,这尤其必要,但必须使用回调或承诺(您必须自己转换为回调)获得结果。