我正在使用Java / Selenium测试JavaScript API。
我在Java端发布这些命令,
executor.executeScript("setName('Hello');");
// Thread.sleep(2000);
String output = (String)executor.executeScript("return getName()");
assertEquals(output, "Hello");
在JavaScript方面,这是一个异步函数,所以它需要一些时间并设置变量。
function setName(msg) {
// simulate async call
setName(function(){name = msg;},1000);
}
我需要等待这个异步函数完成,然后再转到Java中的下一行,执行assertEquals()
。
如果不在Java端使用Thread.sleep()
,有没有办法实现这一目标。
由于
答案 0 :(得分:2)
您可以轻松地要求Selenium等到特定条件成立;确切地说,你有一个替代方案:
new FluentWait<JavascriptExecutor>(executor) {
protected RuntimeException timeoutException(
String message, Throwable lastException) {
Assert.fail("name was never set");
}
}.withTimeout(10, SECONDS)
.until(new Predicate<JavascriptExecutor>() {
public boolean apply(JavascriptExecutor e) {
return (Boolean)executor.executeScript("return ('Hello' === getName());");
}
});
然而,那么你基本上是在测试你刚编码的内容,而且有一个缺点,即如果在你调用name
之前设置了setName
,你就不必等待{{1} } 完成。我过去做过类似事情的一件事是:
在我的测试库中(用setName
垫片取代真正的异步调用),我有这个:
setTimeout
在我的其他库中,每当我需要设置稍后发生的事情时,我会使用window._junit_testid_ = '*none*';
window._junit_async_calls_ = {};
function _setJunitTestid_(testId) {
window._junit_testid_ = testId;
}
function _setTimeout_(cont, timeout) {
var callId = Math.random().toString(36).substr(2);
var testId = window._junit_testid_;
window._junit_async_calls_[testId] |= {};
window._junit_async_calls_[testId][callId] = 1;
window.setTimeout(function(){
cont();
delete(window._junit_async_calls_[testId][callId]);
}, timeout);
}
function _isTestDone_(testId) {
if (window._junit_async_calls_[testId]) {
var thing = window._junit_async_calls_[testId];
for (var prop in thing) {
if (thing.hasOwnProperty(prop)) return false;
}
delete(window._junit_async_calls_[testId]);
}
return true;
}
而不是_setTimeout_
。然后,在我的硒测试中,我做了类似的事情:
window.setTimeout
请注意,如果需要,您可以多次调用// First, this routine is in a library somewhere
public void waitForTest(JavascriptExecutor executor, String testId) {
new FluentWait<JavascriptExecutor>(executor) {
protected RuntimeException timeoutException(
String message, Throwable lastException) {
Assert.fail(testId + " did not finish async calls");
}
}.withTimeout(10, SECONDS)
.until(new Predicate<JavascriptExecutor>() {
public boolean apply(JavascriptExecutor e) {
return (Boolean)executor.executeScript(
"_isTestDone_('" + testId + "');");
}
});
}
// Inside an actual test:
@Test public void serverPingTest() {
// Do stuff to grab my WebDriver instance
// Do this before any interaction with the app
driver.executeScript("_setJunitTestid_('MainAppTest.serverPingTest');");
// Do other stuff including things that fire off what would be async calls
// but now call stuff in my testing library instead.
// ...
// Now I need to wait for all the async stuff to finish:
waitForTest(driver, "MainAppTest.serverPingTest");
// Now query stuff about the app, assert things if needed
}
,只要您需要该测试暂停,直到所有异步操作都完成。
答案 1 :(得分:0)
我怀疑硒的确如此。它只等待页面完全加载,但不是要完成的脚本。您可能希望定义自己的测试步骤&#39;等待结果(并不断轮询页面内容/脚本状态),但一定要设置合理的时间,而不是男性,你的测试会永远挂起脚本错误。