Java Selenium-确定网页是否已在Angular 2+;

Java Selenium-确定网页是否已在Angular 2+;,java,angular,selenium,selenium-webdriver,Java,Angular,Selenium,Selenium Webdriver,我有一个Selenium测试套件,它对许多web应用程序运行Selenium集成测试,有些是用Angular2+编写的,有些是用AngularJS编写的 我们使用自定义的ExpectedCondition和WebDriverWait使测试用例等待AngularJS应用程序完成加载,以避免等待任意时间: private static ExpectedCondition<Boolean> angularIsFinished() { return new ExpectedCondi

我有一个Selenium测试套件,它对许多web应用程序运行Selenium集成测试,有些是用Angular2+编写的,有些是用AngularJS编写的

我们使用自定义的
ExpectedCondition
WebDriverWait
使测试用例等待AngularJS应用程序完成加载,以避免等待任意时间:

private static ExpectedCondition<Boolean> angularIsFinished() {
    return new ExpectedCondition<Boolean>() {
        public Boolean apply(final WebDriver driver) {
            Object result = null;

            while(result == null || result.toString().equals("undefined")) {
                result = ((JavascriptExecutor)driver).executeScript("return typeof angular;");

                try {
                    Thread.sleep(200L);
                } catch (final InterruptedException ex) {
                    logger.error("Error while trying to sleep", ex);
                }
            }

            final String script = "  var el = document.querySelector(\"body\");\n" +
                    "  var callback = arguments[arguments.length - 1];\n" +
                    "  angular.element(el).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);";
            ((JavascriptExecutor)driver).executeAsyncScript(script);
            return true;
        }

        public String toString() {
            return "Wait for AngularJS";
        }
    };
}
private static ExpectedCondition angularIsFinished(){
返回新的ExpectedCondition(){
公共布尔应用(最终WebDriver){
对象结果=空;
while(result==null | | result.toString().equals(“未定义”)){
结果=((JavascriptExecutor)驱动程序);
试一试{
线程。睡眠(200L);
}捕获(最终中断例外){
logger.error(“尝试睡眠时出错”,例如);
}
}
最终字符串script=“var el=document.querySelector(\“body\”);\n+
“var callback=arguments[arguments.length-1];\n”+
“angular.element(el.injector().get('$browser')。notifyWhenNoOutstandingRequests(回调);”;
((JavascriptExecutor)驱动程序);
返回true;
}
公共字符串toString(){
返回“等待AngularJS”;
}
};
}
但是,
返回角度的类型将始终返回
未定义的
。有没有类似于AngularJS的方法可以用来确定Angular2+应用程序何时完成加载

提到使用
NgZone
作为一种可能的解决方案,但是如何通过通过
JavascriptExecutor
执行的脚本来处理这个问题呢?

查看我提出的两种可能的解决方案:

首先,我们有一个选项,找到一个可测试性列表,然后向所有可测试性添加回调,然后等待其中一个将站点标记为可测试(这意味着您的脚本将在任何一个可测试性成为可测试性后继续,而不是等待所有可测试性成为可测试性)

private static ExpectedCondition angular2istable(){
返回(预期条件)驱动程序->{
JavascriptExecutor jsexec=((JavascriptExecutor)驱动程序);
Object result=jsexec.executeAsyncScript(“window.seleniumCallback=arguments[arguments.length-1];\n”+
“如果(window.getAllAngularTestabilities()){\n”+
“window.getAllAngularTestabilities().forEach(函数(可测试性){\n”+
“可测试性.whenStable(window.seleniumCallback(true))\n”+
“}\n”+
“”;\n“+
“}其他{\n”+
“window.seleniumCallback(false)\n”+
"}"
);
返回Boolean.parseBoolean(result.toString());
};
}
第二个选项是专门检查角根元素的可测试性状态:

private static ExpectedCondition angular2ElementIsTestable(final WebElement element) {
    return (ExpectedCondition<Boolean>) driver -> {
        JavascriptExecutor jsexec = ((JavascriptExecutor) driver);
        Object result = jsexec.executeAsyncScript(
                "window.seleniumCallback = arguments[arguments.length -1];\n" +
                        "var element = arguments[0];\n" +
                        "if (window.getAngularTestability && window.getAngularTestability(element)) {\n" +
                        "    window.getAngularTestability(element).whenStable(window.seleniumCallback(true));\n" +
                        "} else {\n" +
                        "    window.seleniumCallback(false)\n" +
                        "}"
        , element);

        return Boolean.parseBoolean(result.toString());
    };
}
private static ExpectedCondition angular2elementistable(最终WebElement){
返回(预期条件)驱动程序->{
JavascriptExecutor jsexec=((JavascriptExecutor)驱动程序);
对象结果=jsexec.executeAsyncScript(
“window.seleniumCallback=参数[arguments.length-1];\n”+
“变量元素=参数[0];\n”+
“如果(window.getAngularTestability&&window.getAngularTestability(元素)){\n”+
“window.getAngularTestability(元素).whenStable(window.seleniumCallback(true));\n”+
“}其他{\n”+
“window.seleniumCallback(false)\n”+
"}"
,元素);
返回Boolean.parseBoolean(result.toString());
};
}
如果要测试站点的特定区域,第二个选项更具针对性,因此更可靠


第三种选择是编写更复杂的东西,跟踪所有可测试性的状态,然后只有在所有可测试性都为真时才触发真正的回调。我还没有这方面的实现。

您可以通过调用例如
document.querySelector('app-root')
来检查它?或任意组件选择器

或者调用
document.readyState
?在完全加载wep页面后,它应该有结果
'complete'
,无论网页是否基于角度。

多亏了,我能够使用
窗口执行类似于量角器的操作。getAllAngularTestabilities
函数。以下是我运行的脚本,用于确定Angular 2+页面是否加载:

var testability = window.getAllAngularTestabilities()[0];
var callback = arguments[arguments.length - 1];
testability.whenStable(callback);
以下是对AngularJS和Angular2+都有效的完整的
ExpectedCondition

private static ExpectedCondition<Boolean> angularIsFinished() {
    return new ExpectedCondition<Boolean>() {
        public Boolean apply(final WebDriver driver) {
            Object result = null;

            boolean isAngular2Plus = false;

            while(result == null || result.toString().equals("undefined")) {
                result = ((JavascriptExecutor)driver).executeScript("return typeof angular;");
                if (result == null || result.toString().equals("undefined")) {
                    result = ((JavascriptExecutor)driver).executeScript("return typeof window.getAngularTestability;");
                    if (result != null && !result.toString().equals("undefined")) {
                        isAngular2Plus = true;
                    }
                }

                try {
                    Thread.sleep(200L);
                } catch (final InterruptedException ex) {
                    logger.error("Error while trying to sleep", ex);
                }
            }

            final String script;
            if (isAngular2Plus) {
                script ="  var testability = window.getAllAngularTestabilities()[0];\n" +
                        "  var callback = arguments[arguments.length - 1];\n" +
                        "  testability.whenStable(callback);";
            } else {
                script ="  var el = document.querySelector(\"body\");\n" +
                        "  var callback = arguments[arguments.length - 1];\n" +
                        "  angular.element(el).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);";
            }
            ((JavascriptExecutor) driver).executeAsyncScript(script);
            return true;
        }

        public String toString() {
            return "Wait for AngularJS";
        }
    };
}
private static ExpectedCondition angularIsFinished(){
返回新的ExpectedCondition(){
公共布尔应用(最终WebDriver){
对象结果=空;
布尔值isAngular2Plus=false;
while(result==null | | result.toString().equals(“未定义”)){
结果=((JavascriptExecutor)驱动程序);
if(result==null | | result.toString().equals(“未定义”)){
结果=((JavascriptExecutor)driver.executeScript(“返回窗口的类型。getAngularTestability;”);
if(result!=null&&!result.toString().equals(“未定义”)){
isAngular2Plus=true;
}
}
试一试{
线程。睡眠(200L);
}捕获(最终整数)
private static ExpectedCondition<Boolean> angularIsFinished() {
    return new ExpectedCondition<Boolean>() {
        public Boolean apply(final WebDriver driver) {
            Object result = null;

            boolean isAngular2Plus = false;

            while(result == null || result.toString().equals("undefined")) {
                result = ((JavascriptExecutor)driver).executeScript("return typeof angular;");
                if (result == null || result.toString().equals("undefined")) {
                    result = ((JavascriptExecutor)driver).executeScript("return typeof window.getAngularTestability;");
                    if (result != null && !result.toString().equals("undefined")) {
                        isAngular2Plus = true;
                    }
                }

                try {
                    Thread.sleep(200L);
                } catch (final InterruptedException ex) {
                    logger.error("Error while trying to sleep", ex);
                }
            }

            final String script;
            if (isAngular2Plus) {
                script ="  var testability = window.getAllAngularTestabilities()[0];\n" +
                        "  var callback = arguments[arguments.length - 1];\n" +
                        "  testability.whenStable(callback);";
            } else {
                script ="  var el = document.querySelector(\"body\");\n" +
                        "  var callback = arguments[arguments.length - 1];\n" +
                        "  angular.element(el).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);";
            }
            ((JavascriptExecutor) driver).executeAsyncScript(script);
            return true;
        }

        public String toString() {
            return "Wait for AngularJS";
        }
    };
}