Nei*_*nin 5 javascript java selenium angularjs selenium-webdriver
为什么要driver.findElement(<some static element ng-if=simplebool>static text</some>).getText()回""?
我有一个角度应用程序,我通过osx通过chromedriver通过osx测试selenium.
我有一些看起来像这样的标记:
<h1 id="my-unique-id" ng-if="model.shouldDisplayThisAttribute">static text</h1>
Run Code Online (Sandbox Code Playgroud)
我经常得到:
assert(driver.findElement(By.id("my-unique-id").getText().contains("static text");
Run Code Online (Sandbox Code Playgroud)
收益:
java.lang.AssertionError: Not true that <""> contains <"static text">
Run Code Online (Sandbox Code Playgroud)
比如,30%的时间.
我不明白该元素的.getText()如何评估为"",所以我假设angular是$ digesting或$ compiling page.没关系.没关系.没关系.
我想知道angular什么时候完成了$ compiling和$ digesting和$ watching,所以我可以查看页面看看是什么.
如果我添加:
(function()
function angularAppearsToBeIdle(callback) {
var untilNextDigest,
isIdle = angular.element(document.body).scope().$watch(function () {
clearTimeout(untilNextDigest);
untilNextDigest = setTimeout(function () {
isIdle();
callback('done');
}, 100);
});
}
angularAppearsToBeIdle(console.log.bind(console));
}());
Run Code Online (Sandbox Code Playgroud)
在我的页面中,我看到了我期待它们时的console.log消息.
如果我将其粘贴到控制台中:
(function() {
function angularAppearsToBeIdle(callback) {
var untilNextDigest,
isIdle = angular.element(document.body).scope().$watch(function () {
clearTimeout(untilNextDigest);
untilNextDigest = setTimeout(function () {
isIdle();
callback('done');
}, 100);
});
}
angularAppearsToBeIdle(console.log.bind(console));
}());
Run Code Online (Sandbox Code Playgroud)
我得到'未定义'.
最终,我想做的是来自Java:
@Test
public void clickOnSomethingThatIsProbablyNotGoingToChange(driver.findElement(By.id("some-id"));
private WebElement idleElement() {
new WebDriverWait(driver, 30).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver input) {
Object result = ((JavascriptExecutor) driver).executeScript("return window.angularAppearsToBeIdle;");
return result.equals("idle");
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试了以下内容,但没有Selenium做这样的事情的例子:
public void waitForAngular() {
((JavascriptExecutor) driver).executeScript(
" window.angularAppearsToBeIdle = 'not idle'; ");
((JavascriptExecutor) driver).executeScript(
" window.signalThatAngularAppearsToBeIdle = function(signal) { " +
" var untilNextDigest, " +
" isIdle = angular.element(document.body).scope().$watch(function () { " +
" clearTimeout(untilNextDigest); " +
" untilNextDigest = setTimeout(function () { " +
" isIdle(); " +
" signal = 'idle'; " +
" }, 100); " +
" }); " +
" } ");
driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
((JavascriptExecutor) driver).executeAsyncScript(
" var callback = arguments[arguments.length - 1]; " +
" signalThatAngularAppearsToBeIdle(callback) "
,
" window.angularAppearsToBeIdle ");
new WebDriverWait(driver, 30).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver input) {
Object result = ((JavascriptExecutor) driver).executeScript("return window.angularAppearsToBeIdle;");
return result.equals("idle");
}
});
Run Code Online (Sandbox Code Playgroud)
如果角度正忙着做什么,我如何从Selenium中检测到?
您将需要编写一个自定义的ExpectedCondition,它会查询角度以查看是否已完成.这是我之前准备的一个:
public static ExpectedCondition angularHasFinishedProcessing() {
return new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
String hasAngularFinishedScript = "var callback = arguments[arguments.length - 1];\n" +
"var el = document.querySelector('html');\n" +
"if (!window.angular) {\n" +
" callback('false')\n" +
"}\n" +
"if (angular.getTestability) {\n" +
" angular.getTestability(el).whenStable(function(){callback('true')});\n" +
"} else {\n" +
" if (!angular.element(el).injector()) {\n" +
" callback('false')\n" +
" }\n" +
" var browser = angular.element(el).injector().get('$browser');\n" +
" browser.notifyWhenNoOutstandingRequests(function(){callback('true')});\n" +
"}";
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
String isProcessingFinished = javascriptExecutor.executeAsyncScript(hasAngularFinishedScript).toString();
return Boolean.valueOf(isProcessingFinished);
}
};
}
Run Code Online (Sandbox Code Playgroud)
这假设你已经在你的html元素上定义了ng-app.如果您在DOM中的其他位置定义它,则需要更新上面的代码.这几乎是从量角器中偷来的,它正在检查是否有任何未完成的ajax请求并检查是否有角度认为它处于可测试状态.
重要的是将此JavaScript代码段作为异步脚本执行,因为angular正在使用promises在准备好时触发回调.如果不将其作为异步脚本运行,则无法运行.
您还需要在驱动程序对象上设置脚本超时,这是selenium在抛出超时异常之前等待回调完成的时间.您可以按如下方式进行设置:
driver.manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)
然后就像将ExpectedCondition插入等待中这样简单:
WebDriverWait wait = new WebDriverWait(driver, 15, 100);
wait.until(angularHasFinishedProcessing());
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.