Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angularjs 用硒检测鳗鲡_Angularjs_Selenium_C# 4.0_Phantomjs_End To End_Pageobjects - Fatal编程技术网

Angularjs 用硒检测鳗鲡

Angularjs 用硒检测鳗鲡,angularjs,selenium,c#-4.0,phantomjs,end-to-end,pageobjects,Angularjs,Selenium,C# 4.0,Phantomjs,End To End,Pageobjects,我在堆栈ASP MVC+AngularJS上有一个SPA应用程序,我想测试UI。 目前,我正在尝试使用PhantomJS和WebKit驱动程序开发Selenium 这是一个带有单个元素的测试页面视图示例。列表项从服务器动态加载,并以角度为界 <div id="items"> <li>text</li> <li>text2</li> </div> 此时没有加载的元素,并且_driver.PageSource不

我在堆栈ASP MVC+AngularJS上有一个SPA应用程序,我想测试UI。 目前,我正在尝试使用PhantomJS和WebKit驱动程序开发Selenium

这是一个带有单个元素的测试页面视图示例。列表项从服务器动态加载,并以角度为界

<div id="items">
    <li>text</li>
    <li>text2</li>
</div>
此时没有加载的元素,并且_driver.PageSource不包含元素


如何等待项目加载?请不要建议
Thread.Sleep()

如果您使用的是AngularJS,那么使用量角器是个好主意

如果使用量角器,则可以使用它的waitForAngular()方法,该方法将等待http请求完成。在对元素执行操作之前,等待元素显示仍然是一种很好的做法,这取决于您的语言和实现,在同步语言中可能会出现这种情况

WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));

除了埃迪奇的建议。如果您测试AngularJS应用程序,我强烈建议您考虑量角器

量角器将帮助您解决等待问题(同步、异步)。不过,也有一些注意事项

1-您需要用javascript开发测试


2-在处理流时有一些不同的机制

这将等待页面加载/jquery.ajax(如果存在)和$http调用,以及任何伴随的摘要/呈现周期,将其丢弃在实用程序函数中并等待

/*C#示例
var pageLoadWait=新的WebDriverWait(WebDriver,TimeSpan.FromSeconds(超时));
PageLoad,等等(
(司机)=>
{
返回(bool)JS.ExecuteScript(
@"*/
试一试{
如果(document.readyState!==“完成”){
return false;//尚未加载页面
}
if(window.jQuery){
if(window.jQuery.active){
返回false;
}else if(window.jQuery.ajax&&window.jQuery.ajax.active){
返回false;
}
}
如果(窗口角度){
如果(!window.qa){
//用于在加载完成后跟踪渲染周期完成
window.qa={
doneRendering:错误
};
}
//获取此应用程序的角度喷油器(如有必要,请更换滤芯)
var injector=window.angular.element('body').injector();
//用于这些检查的存储提供程序
var$rootScope=injector.get(“$rootScope”);
var$http=injector.get(“$http”);
var$timeout=injector.get(“$timeout”);
//检查是否有摘要
if($rootScope.$$phase==='$apply'| |$rootScope.$$phase==='$digest'| |$http.pendingRequests.length!==0){
window.qa.doneRendering=false;
返回false;//角度消化或加载数据
}
如果(!window.qa.doneRendering){
//设置超时以将角度渲染标记为完成
$timeout(函数(){
window.qa.doneRendering=true;
}, 0);
返回false;
}
}
返回true;
}捕获(ex){
返回false;
}
/*");
});*/

我编写了以下代码,它帮助我解决了异步竞争条件失败的问题

$window._docReady = function () {
        var phase = $scope.$root.$$phase;
        return $http.pendingRequests.length === 0 && phase !== '$apply' && phase !== '$digest';
    }
现在在selenium PageObject模型中,您可以等待

Object result = ((RemoteWebDriver) driver).executeScript("return _docReady();");
                    return result == null ? false : (Boolean) result;

如果您的web应用程序确实如您所说是使用Angular创建的,那么进行端到端测试的最佳方法就是使用Angular

在内部,量角器使用自己的
waitForAngular
方法,以确保量角器自动等待Angular完成对DOM的修改

因此,在正常情况下,您永远不需要在您的测试用例中编写显式的
wait
:量角器为您这样做

您可以查看教程以了解如何设置量角器

如果你想认真使用量角器,你会想采用。如果你想要一个这样的例子,可以看看我的有角度的电话猫


使用量角器,您可以使用Javascript编写测试(量角器确实基于节点),而不是使用C#,但作为回报,量角器会处理等待您的所有内容。

创建一个新类,让您可以确定使用AngularJS的网站是否已完成AJAX调用,如下所示:

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

public class AdditionalConditions {
    public static ExpectedCondition<Boolean> angularHasFinishedProcessing() {
        return new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driver) {
                return Boolean.valueOf(((JavascriptExecutor) driver).executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)").toString());
            }
        };
    }
}

对于包含iFrame并使用AnglularJS开发的HTML页面的特殊问题,以下技巧为我节省了大量时间: 在DOM中,我清楚地看到有一个iframe包装了所有内容。 所以下面的代码应该可以工作:

driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");
但它不起作用,并告诉我类似“无法切换到框架。窗口已关闭”。 然后我将代码修改为:

driver.switchTo().defaultContent();
driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");
这之后一切都很顺利。 很明显,Angular在iframes中弄乱了一些东西,在加载页面之后,当您希望驱动程序聚焦于默认内容时,Angular frame已经移除了一些驱动程序。
希望这能对你们中的一些人有所帮助。

你们可以从量角器中找到有用的代码片段。此函数将一直阻止,直到完成页面渲染。这是沙赫扎伊布·萨利姆答案的变体,只是他正在投票,我正在设置回调

def wait_for_angular(self, selenium):
    self.selenium.set_script_timeout(10)
    self.selenium.execute_async_script("""
        callback = arguments[arguments.length - 1];
        angular.element('html').injector().get('$browser').notifyWhenNoOutstandingRequests(callback);""")
ng应用程序中的任何元素替换为“html”


如果您不想将整个开关切换到量角器,但您确实想等待我推荐使用的(Java)Angular,那么它来自于。它是基于量角器的,但你不必进行切换

我通过编写一个actions类修复了这个问题,在执行操作(单击、填充、检查等)之前,我在该类中等待Angular(使用ngWebDriver的waitForAngularRequestsToFinish())


有关代码片段,请参见

我们遇到了一个类似的问题,我们的内部框架被用于测试多个站点,其中一些使用JQuery,一些使用AngularJS(1甚至有一个混合版本!)。我们的框架是用C#编写的,因此执行的任何JScript都必须在最小的块中完成(出于调试目的)。事实上,上面的答案有很多,并将它们混合在一起(因此,在@npjohns中应该有信用的地方就有信用)。下面是对我们所做工作的解释:

如果已加载HTML DOM,则以下内容返回true/false:

        public bool DomHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
    {

        var hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
        while (hasThePageLoaded == null || ((string)hasThePageLoaded != "complete" && timeout > 0))
        {
            Thread.Sleep(100);
            timeout--;
            hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
            if (timeout != 0) continue;
            Console.WriteLine("The page has not loaded successfully in the time provided.");
            return false;
        }
        return true;
    }
public bool AngularHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
        {
    string HasAngularLoaded =
        @"return (window.angular !== undefined) && (angular.element(document.body).injector() !== undefined) && (angular.element(document.body).injector().get('$http').pendingRequests.length === 0)";            
    var hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                while (hasTheAngularLoaded == null || (!(bool)hasTheAngularLoaded && timeout > 0))
                {
                    Thread.Sleep(100);
                    timeout--;
                    hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                    if (timeout != 0) continue;
                    Console.WriteLine(
                        "Angular is being used by the site but has failed to successfully load.");
                    return false;

                }
                return (bool)hasTheAngularLoaded;
        }
然后我们检查JQuery是否正确
def wait_for_angular(self, selenium):
    self.selenium.set_script_timeout(10)
    self.selenium.execute_async_script("""
        callback = arguments[arguments.length - 1];
        angular.element('html').injector().get('$browser').notifyWhenNoOutstandingRequests(callback);""")
        public bool DomHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
    {

        var hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
        while (hasThePageLoaded == null || ((string)hasThePageLoaded != "complete" && timeout > 0))
        {
            Thread.Sleep(100);
            timeout--;
            hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
            if (timeout != 0) continue;
            Console.WriteLine("The page has not loaded successfully in the time provided.");
            return false;
        }
        return true;
    }
public bool IsJqueryBeingUsed(IJavaScriptExecutor jsExecutor)
    {
        var isTheSiteUsingJQuery = jsExecutor.ExecuteScript("return window.jQuery != undefined");
        return (bool)isTheSiteUsingJQuery;
    }
public bool JqueryHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
        {
                var hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
                while (hasTheJQueryLoaded == null || (!(bool) hasTheJQueryLoaded && timeout > 0))
                {
                    Thread.Sleep(100);
                timeout--;
                    hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
                    if (timeout != 0) continue;
                    Console.WriteLine(
                        "JQuery is being used by the site but has failed to successfully load.");
                    return false;
                }
                return (bool) hasTheJQueryLoaded;
        }
    public bool AngularIsBeingUsed(IJavaScriptExecutor jsExecutor)
    {
        string UsingAngular = @"if (window.angular){
        return true;
        }";            
        var isTheSiteUsingAngular = jsExecutor.ExecuteScript(UsingAngular);
        return (bool) isTheSiteUsingAngular;
    }
public bool AngularHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
        {
    string HasAngularLoaded =
        @"return (window.angular !== undefined) && (angular.element(document.body).injector() !== undefined) && (angular.element(document.body).injector().get('$http').pendingRequests.length === 0)";            
    var hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                while (hasTheAngularLoaded == null || (!(bool)hasTheAngularLoaded && timeout > 0))
                {
                    Thread.Sleep(100);
                    timeout--;
                    hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                    if (timeout != 0) continue;
                    Console.WriteLine(
                        "Angular is being used by the site but has failed to successfully load.");
                    return false;

                }
                return (bool)hasTheAngularLoaded;
        }
    var jquery = !IsJqueryBeingUsed(javascript) || wait.Until(x => JQueryHasLoaded(javascript));
    var angular = !AngularIsBeingUsed(javascript) || wait.Until(x => AngularHasLoaded(javascript));
// Wait for Angular to Finish
function angularReady(): any  {
  return $browser.executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)")
     .then(function(angularIsReady) {                        
                    return angularIsReady === true;
                  });
}

$browser.wait(angularReady, 5000).then(...);
public void PageCallingUtility()
{
    if (DomHasLoaded() == true)
    {
        if (IsJqueryBeingUsed() == true)
        {
            JqueryHasLoaded();
        }

        if (AngularIsBeingUsed() == true)
        {
            AngularHasLoaded();
        }
    }
}