javascript - 使用 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));
堆栈跟踪
未知错误:未定义 foo(会话信息:chrome=56.0.2924.87)(驱动程序信息:chromedriver=2.25.426923(0390b88869384d6eb0d5d09729679f934aab9eed),平台=Windows NT 6.1.7601 SP1 x86_64)(警告:服务器未提供任何堆栈跟踪信息)命令持续时间或超时:51 毫秒构建信息:版本:'2.53.0',修订:'35ae25b',时间:'2016-03-15 17:00:58' 系统信息:主机:'WV-VC104- 027', ip: '{ip}', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.8.0_151' 驱动信息: org. openqa.selenium.chrome.ChromeDriver 功能 [{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,版本=56.0.292.87,版本=56.0.292 platform=XP,browserConnectionEnabled=false,nativeEvents=true,acceptSslCerts=true,locationContextEnabled=true,webStorageEnabled=true,browserName=chrome,takeScreenshot=true,javascriptEnabled=true,cssSelectorsEnabled=true}]会话ID:a7734312eff62fe452a53895b221a58dlocationContextEnabled=true,webStorageEnabled=true,browserName=chrome,takeScreenshot=true,javascriptEnabled=true,cssSelectorsEnabled=true}] 会话 ID:a7734312eff62fe452a53895b221a58dlocationContextEnabled=true,webStorageEnabled=true,browserName=chrome,takeScreenshot=true,javascriptEnabled=true,cssSelectorsEnabled=true}] 会话 ID:a7734312eff62fe452a53895b221a58d
当我尝试设置时,foo.bar
我无法获得对变量的引用,因为它不是全局定义的,并且隐藏在 AngularJS 源代码中的某个地方。我试图取消索引并寻找变量,但我似乎找不到它。我想通过 手动设置foo.bar
变量,JavascriptExecutor
但无法获得对变量的引用。我将如何找到然后设置变量?
如果这似乎是触发此错误的错误方式ng-click
,我愿意接受想法。我确信 Protractor 有办法处理这个问题,但是这个 AngularJS 应用程序部署在企业环境中,并且几个月来一直试图让业务方批准这项技术。我被硒困住了。帮助...
解决方案
直接回答你的问题[不要用它来解决你的问题:)]
Angular 具有独立的变量作用域。因此您需要获取作用域并在其中设置变量。
angular.element("#id").scope().foo.bar = true;
但不要将它用于您的情况。当您在系统级别测试应用程序时,您必须像用户一样测试它们。
推荐答案:等待java中的角度可测试性
无论量角器可以处理什么,您的 java 测试也可以处理。两者都是硒绑定的包装器。最终,所有 selenese 代码都在您测试的同一浏览器中执行。
waitForAngularMethod
是您在测试中遗漏的最不可避免的方法。好消息是您可以在 expilcit 等待中使用 JavaScriptExecutor 执行相同类型的 javascript。
如果你是 javascript 爱好者,可以参考 protractor 中的waitForangular方法实现。这只是一个简单的验证检查并使用回调等待。
您用于为 waitforangular 创建预期条件的 java 代码
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);
等待 Angular Javascript(为您的 Java 执行而修改。但我没有检查它):
该方法需要两个属性,根定位器挂钩和回调。我已将回调设置为一个简单的函数 return 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
推荐阅读
- python - MYSQL 工作台 8 迁移向导错误“SystemError: TypeError(”'>' not supported between 'NoneType' and 'int'")”
- sap-fiori - 强制注销通过 Fiori 启动板登录的用户
- pandas - 如果第一列的值为空,如何删除一行?
- javascript - 如何从 .js 文件中导出对象以在主文件中使用它
- groovy - [Jmeter] 源单元“Script1.groovy”中的“语义分析”阶段异常 不支持的类文件主要版本 61
- r - 错误:缺少参数“expr”,没有默认值
- html - 包装时打破字母但不打破单词
- javascript - 将 Firebase 身份验证用于 Web 应用程序的最佳做法是什么?
- javascript - 过滤器:反转()页面上的所有项目,除了一个
- javascript - 使用变量来更改对象名称,并使用扩展运算符(Reactjs)