使用Java Selenium JavascriptExecutor访问AngularJS变量

这是一个带有AngularJS ng-click属性的div,它在单击div时设置变量.

<div id="id"
     ng-click="foo.bar = true;">
     Set bar variable on foo object to true
</div>

下面是一些使用Selenium单击div元素的Java代码.

By upload = By.id("id");
driver.findElement(uploadCensus).click();

当我运行Java代码时,AngularJS会永久地挂起.我想点击div时没有设置foo.bar所以这里是一些直接设置变量的代码.

By upload = By.id("id");
((JavascriptExecutor) driver)
    .executeScript("foo.bar = true;",   
    driver.findElement(upload));

堆栈跟踪

unknown error: foo is not defined (Session info: chrome=56.0.2924.87)
(Driver info: chromedriver=2.25.426923
(0390b88869384d6eb0d5d09729679f934aab9eed),platform=Windows NT
6.1.7601 SP1 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 51 milliseconds
Build info: version: ‘2.53.0’, revision: ’35ae25b’, time: ‘2016-03-15
17:00:58’ System info: host: ‘WV-VC104-027’, ip: ‘{ip}’, os.name:
‘Windows 7’, os.arch: ‘amd64’, os.version: ‘6.1’, java.version:
‘1.8.0_151’ Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{applicationCacheEnabled=false, rotatable=false,
mobileEmulationEnabled=false, networkConnectionEnabled=false,
chrome={chromedriverVersion=2.25.426923
(0390b88869384d6eb0d5d09729679f934aab9eed),
userDataDir=C:\Users{user}\AppData\Local\Temp\scoped_dir5600_4225},
takesHeapSnapshot=true, pageLoadStrategy=normal,
databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false,
version=56.0.2924.87, platform=XP, browserConnectionEnabled=false,
nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true,
webStorageEnabled=true, browserName=chrome, takesScreenshot=true,
javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID:
a7734312eff62fe452a53895b221a58d

当我尝试设置foo.bar时,我无法获得对变量的引用,因为它不是全局定义的,而是隐藏在AngularJS源代码中的某个地方.我试图消除索引并寻找变量,但我似乎无法找到它.我想通过JavascriptExecutor手动设置foo.bar变量,但无法获取对变量的引用.我如何找到然后设置变量?

如果这似乎是触发此ng-click的错误方式,我对这些想法持开放态度.我相信Protractor有办法处理这个问题,但是这个AngularJS应用程序部署在企业环境中,并且几个月来一直试图让业务部门批准该技术.我被Selenium困住了.救命…

最佳答案 直接回答你的问题[不要用它来为你的情况:)]

Angular已经隔离了变量scope.So你需要获取范围并设置变量.

angular.element("#id").scope().foo.bar = true;

但是不要在你的情况下使用它.在系统级别测试应用程序时,必须像用户一样测试它们.

推荐答案:等待java中的角度测试

无论量角器能处理什么,你的java测试也可以.两者都是硒结合的包装物.最终所有selenese代码都在您测试的同一浏览器中执行.

waitForAngularMethod是你在测试中遗漏的最不可避免的方法.好的是你可以在expilcit等中使用JavaScriptExecutor执行相同类型的javascript.

如果你是javascript爱好者,你可以在量角器中引用waitForangular方法实现.它只是一个简单的验证检查,并使用回调等待.

您的java代码,用于为waitforangular创建预期的condrion

String waitForAngularJs ="Your javascript goes here"; // as it is lengthy read it from file and store here.
ExpectedCondition<Boolean> waitForAngular= new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                return ((JavascriptExecutor) driver).executeAsyncScript(waitForAngularJs).equals(true);
            }
};

 WebDriverWait wait = new WebDriverWait(driver, 60);
 wait.until(waitForAngular);

等待角度Javascript(为Java执行而修改.但我没有检查它):

该方法需要两个属性,根定位器挂钩和回调.我已将回调设置为简单的函数返回true并与根定位器挂钩,即[ng-app].

var testCallback = function() {
  return true;
 };

    // Wait for angular1 testability first and run waitForAngular2 as a callback
    var waitForAngular1 = function(callback) {

      if (window.angular) {
        var hooks = window.angular.element('[ng-app]');
        if (!hooks){
          callback();  // not an angular1 app
        }
        else{
          if (hooks.$$testability) {
            hooks.$$testability.whenStable(callback);
          } else if (hooks.$injector) {
            hooks.$injector.get('$browser')
                .notifyWhenNoOutstandingRequests(callback);
          } else if (!rootSelector) {
            throw new Error(
                'Could not automatically find injector on page: "' +
                window.location.toString() + '".  Consider using config.rootEl');
          } else {
            throw new Error(
                'root element (' + rootSelector + ') has no injector.' +
                ' this may mean it is not inside ng-app.');
          }
        }
      }
      else {callback();}  // not an angular1 app
    };

    // Wait for Angular2 testability and then run test callback
    var waitForAngular2 = function() {
      if (window.getAngularTestability) {
        if (rootSelector) {
          var testability = null;
          var el = document.querySelector(rootSelector);
          try{
            testability = window.getAngularTestability(el);
          }
          catch(e){}
          if (testability) {
            testability.whenStable(testCallback);
            return;
          }
        }

        // Didn't specify root element or testability could not be found
        // by rootSelector. This may happen in a hybrid app, which could have
        // more than one root.
        var testabilities = window.getAllAngularTestabilities();
        var count = testabilities.length;

        // No angular2 testability, this happens when
        // going to a hybrid page and going back to a pure angular1 page
        if (count === 0) {
          testCallback();
          return;
        }

        var decrement = function() {
          count--;
          if (count === 0) {
            testCallback();
          }
        };
        testabilities.forEach(function(testability) {
          testability.whenStable(decrement);
        });

      }
      else {testCallback();}  // not an angular2 app
    };

    if (!(window.angular) && !(window.getAngularTestability)) {
      // no testability hook
      throw new Error(
          'both angularJS testability and angular testability are undefined.' +
          '  This could be either ' +
          'because this is a non-angular page or because your test involves ' +
          'client-side navigation, which can interfere with Protractor\'s ' +
          'bootstrapping.  See http://git.io/v4gXM for details');
    } else {waitForAngular1(waitForAngular2);}  // Wait for angular1 and angular2
// Testability hooks sequentially

为什么我们需要等待角度和逻辑背后

为什么我们需要这个因为angular使用html模板,双向数据绑定,ajax请求和路由.因此,在页面导航之后,我们必须等待所有这些操作(请求和承诺)完成.否则html将不会像您的情况那样按预期响应.

检查角度测试

即检查角度的可测性.对于这个角度本身提供了一种方法.

要根据元素进行检查,

 window.getAngularTestability(el).whenStable(callback); //Here el is element to be valiated.

检查所有测试,

 window.getAllAngularTestabilities();
   testabilities.forEach(function(testability) {
        testability.whenStable(callback);
});

等待所有http待处理请求完成

在检查角度测试之前,我们可以通过以下行确保没有待处理的http请求.

angular.element(document).injector().get('$http').pendingRequest.length
点赞