我使用量角器/ jasmine2时遇到了Stale Element Reference Exception的问题。
我的规格:
var LoginPage = require('../pages/login_page.js');
var WelcomePage = require('../pages/welcome_page.js');
describe('Test -> testing something', function () {
var loginPage;
var EC = protractor.ExpectedConditions;
var waitTimeout = 10000;
function logIn() {
loginPage.setUser('user');
loginPage.setPassword('password');
loginPage.login();
}
beforeEach(function () {
browser.ignoreSynchronization = true;
loginPage = new LoginPage();
browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout);
logIn();
var welcomePage = new WelcomePage();
browser.wait(EC.visibilityOf(welcomePage.usersButton), waitTimeout);
welcomePage.usersButton.click();
});
问题是当我想点击usersButton时,在lastEach函数的最后一行上随机出现StaleElementReferenceException。 不知道为什么ExpectedCondition不起作用(尝试了不同的EC,如presenceOf,elementToBeClickable等,但没有解决问题)。
请参阅定义了usersButton以供参考的页面:
'use strict';
var WelcomePage = function () {
};
WelcomePage.prototype = Object.create({}, {
usersButton: {
get: function () {
return element(by.css('#users a'));
}
}
});
module.exports = WelcomePage;
我认为需要一些通用的retry_mechanism来处理它,任何人都有类似的问题吗?
最后写了这样的函数
var clickOn = function (element) {
browser.wait(EC.visibilityOf(element), waitTimeout).then(function() {
element.click();
});}
这样调用:
clickOn(welcomePage.usersButton);
更新: 已经多次测试过了,当我在selenium网格上运行测试时,我仍然在这个确切的元素上得到Stale Element异常。所以提供的解决方案不起作用......
Failed: stale element reference: element is not attached to the page document (Session info: chrome=45.0.2454.93) (Driver info: chromedriver=2.19.346078 (6f1f0cde889532d48ce8242342d0b84f94b114a1),platform=Windows NT 6.1 SP1 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 15 milliseconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html Build info: version: '2.47.1', revision: '411b314', time: '2015-07-30 03:03:16' System info: host: 'ITHFPC17', ip: '10.98.0.48', os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.8.0_40' Driver info: org.openqa.selenium.chrome.ChromeDriver Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, chrome={userDataDir=C:\Users\SELENI~1\AppData\Local\Temp\scoped_dir2384_11396}, takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=45.0.2454.93, platform=XP, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID: 3244710644015ee170986333564ab806
Failed: Wait timed out after 10032ms
接下来的方法是等到元素存在,之后如果它是可见的,之后如果它是可点击的......但它也不起作用。奇怪的是,在selenium网格上一切正常,但是当我尝试在本地运行测试然后获得之前提到的异常时。
exports.clickOn = function (element) {
browser.wait(EC.presenceOf(element), waitTimeout).then(function () {
browser.wait(EC.visibilityOf(element), waitTimeout)
}).then(function () {
browser.wait(EC.elementToBeClickable(element), waitTimeout)
}).then(function () {
element.click();
});
};
任何人都知道如何处理它? ......我被困住了。
答案 0 :(得分:1)
通过解析等待elementToBeClickable()
函数返回的承诺,等待元素有资格被点击。还要确保完成click()
之前的操作,以便量角器可以按预期找到元素。可能将所有操作链接到彼此可能是一个很好的解决方案。这样可以避免StaleElementReferenceException
错误。这是怎样的 -
browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout).then(function(){
logIn();
}).then(function(){
var welcomePage = new WelcomePage();
}).then(function(){
browser.wait(EC.elementToBeClickable(welcomePage.usersButton), waitTimeout).then(function(){
welcomePage.usersButton.click();
});
});
希望它有所帮助。
答案 1 :(得分:1)
最后,我通过添加“不太好”来解决这个问题'简单的重试机制。
exports.clickOnElementWithWait = function (element, attempts) {
if (attempts == null) {
attempts = 10;
}
return element.click().then(function (found) {
}, function (err) {
if (attempts > 0) {
browser.sleep(100);
return exports.clickOnElementWithWait(element, attempts - 1);
} else {
throw err;
}
});
};
更新:不幸的是它随机工作。异常数量减少但仍然......
我有Java代码,当我在纯selenium / junit中体验它并想知道它是否有任何免费工具将其转换为javascript时帮助了我? 有人可以帮帮我吗?
public class RetryMechanism {
private static final int DEFAULT_RETRY_NR = 20;
private static final long DEFAULT_WAIT_TIME_IN_MILLI = 1000;
private int numberOfRetries;
private int numberOfTriesLeft;
private static long timeToWait;
public RetryMechanism() {
this(DEFAULT_RETRY_NR, DEFAULT_WAIT_TIME_IN_MILLI);
}
public RetryMechanism(int numberOfRetries, long timeToWait) {
this.numberOfRetries = numberOfRetries;
numberOfTriesLeft = numberOfRetries;
this.timeToWait = timeToWait;
}
public boolean shouldRetry() {
return numberOfTriesLeft > 0;
}
public void errorOccurred(Throwable throwable) throws Exception {
numberOfTriesLeft--;
if (!shouldRetry()) {
throw new Exception("Retry Failed: Total " + numberOfRetries
+ " attempts made at interval " + getTimeToWait()
+ "ms.\n"
+ "Error message is : " + throwable.getMessage()
+ "\n"
+ "Caused by : " + throwable.getCause());
}
waitUntilNextTry();
}
public static long getTimeToWait() {
return timeToWait;
}
public static void waitUntilNextTry() {
try {
Thread.sleep(getTimeToWait());
} catch (InterruptedException ignored) {
}
}
public interface Action {
void doJob();
}
public static void retry(Action action) throws Exception {
RetryMechanism retry = new RetryMechanism();
while (retry.shouldRetry()) try {
action.doJob();
break;
} catch (Exception e) {
retry.errorOccurred(e);
}
}
}