我一直在使用selenium
(主要是python bindings和protractor
)很长一段时间,每次我需要执行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()
?
问题是硒特异性,但与语言无关。
答案 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
。
由于您使用过量角器,我会以此为例。
量角器在get
和waitForAngular
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}},但该返回值不会立即可用。如果您不能轮询结果,这尤其必要,但必须使用回调或承诺(您必须自己转换为回调)获得结果。