如果 Angular 正在做......从硒中检测
Posted
技术标签:
【中文标题】如果 Angular 正在做......从硒中检测【英文标题】:Detect from selenium if angular is doing ... stuff 【发布时间】:2015-11-27 12:23:03 【问题描述】:为什么driver.findElement(<some static element ng-if=simplebool>static text</some>).getText()
总是返回“”?
我有一个 Angular 应用程序,我正在通过 chromedriver 通过 osx 上的 java 使用 selenium 进行测试。
我有一些看起来像这样的标记:
<h1 id="my-unique-id" ng-if="model.shouldDisplayThisAttribute">static text</h1>
我经常得到:
assert(driver.findElement(By.id("my-unique-id").getText().contains("static text");
屈服:
java.lang.AssertionError: Not true that <""> contains <"static text">
比如,30% 的时间。
我不明白该元素的 .getText() 如何评估为“”,所以我假设 angular 是 $digesting 或 $compiling 页面。没关系。没关系。没关系。
我想知道 Angular 什么时候完成了 $compile 和 $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));
());
在我的页面上,我在预期的时间看到了 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));
());
我得到“未定义”。
最终,我想做的是来自 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");
我尝试了以下方法,但没有 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");
);
如果 Angular 忙于做事,我如何从 Selenium 中检测到?
【问题讨论】:
首先请更正您的以下代码assert(driver.findElement(By.id("my-unique-id").getText().contains("expected"); 即使没有括号也正确匹配。否则会误导其他人。 我严重怀疑任何人都不会理解我的问题。如果人们不明白,我会更新我的问题...... 请更新问题标题,使其更能描述实际问题。 Protractor.js 这样做github.com/angular/protractor/blob/…,Ardesco 的回答是对 Selenium 的一个很好的翻译。 【参考方案1】:您将需要编写一个自定义的 ExpectedCondition 来查询 Angular 以查看它是否已完成。这是我之前准备的:
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);
;
这是假设您在 html 元素上定义了 ng-app。如果你在 DOM 的其他地方定义它,你需要更新上面的代码。这几乎是从量角器偷来的,它正在检查是否有任何未完成的 ajax 请求并检查 Angular 是否认为它处于可测试状态。
重要的部分是将这个 JavaScript sn-p 作为异步脚本执行,因为 Angular 使用 Promise 在准备好时触发回调。如果您不将其作为异步脚本运行,它将无法工作。
您还需要在驱动程序对象上设置脚本超时,这是 selenium 在抛出超时异常之前等待回调完成的时间量。可以这样设置:
driver.manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS);
然后就像将这个 ExpectedCondition 插入到一个等待中一样简单:
WebDriverWait wait = new WebDriverWait(driver, 15, 100);
wait.until(angularHasFinishedProcessing());
希望这会有所帮助。
【讨论】:
【参考方案2】:我正在用 C#.Net 编写,所以我不得不翻译 Ardesco 的答案:
static class HelperFunctions
public static bool AngularHasFinishedProcessing(IWebDriver driver)
string HasAngularFinishedScript =
@"var callback = arguments[arguments.length - 1];
var el = document.querySelector('html');
if (!window.angular)
callback('False')
if (angular.getTestability)
angular.getTestability(el).whenStable(function()callback('True'));
else
if (!angular.element(el).injector())
callback('False')
var browser = angular.element(el).injector().get('$browser');
browser.notifyWhenNoOutstandingRequests(function()callback('True'));
";
IJavaScriptExecutor javascriptExecutor = (IJavaScriptExecutor)driver;
return Convert.ToBoolean(javascriptExecutor.ExecuteAsyncScript(HasAngularFinishedScript));
为了称呼它,我用:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until((d) => return HelperFunctions.AngularHasFinishedProcessing(driver); );
【讨论】:
【参考方案3】:混合使用 Python 2.7:
class angular_is_ready(object):
script = """var callback = arguments[arguments.length - 1];
var el = document.querySelector('html');
if (!window.angular)
callback(false)
if (angular.getTestability)
angular.getTestability(el).whenStable(function()callback(true));
else
if (!angular.element(el).injector())
callback(false)
var browser = angular.element(el).injector().get('$browser');
browser.notifyWhenNoOutstandingRequests(function()callback(true));
;"""
def __call__(self, driver):
try:
return driver.execute_async_script(self.script)
except:
return False
# Define driver and timeout,
# then use the condition like so:
WebDriverWait(driver, timeout).until(angular_is_ready)
【讨论】:
以上是关于如果 Angular 正在做......从硒中检测的主要内容,如果未能解决你的问题,请参考以下文章