我正在运行node.js和Selenium WebDriverJS。我的一个测试失败,出现以下错误:
UnknownError: unknown error: Runtime.evaluate threw exception: Error: element is not attached to the page document
据我所知,这实际上是一个StaleElementReferenceException,但我找不到可靠的解决方法。我没有成功尝试以下内容:
在找到并单击元素之前等待元素出现在页面上
waitForElement: function (selector, timeout) {
if (typeof(timeout) === 'undefined') { timeout = 3000; }
driver.wait(function() {
return driver.findElements(selector).then(function(list) {
return list.length > 0;
});
}, timeout);
}
driver.sleep(1000)
).findElement()
)
使用promise链捕获任何错误并尝试重新点击元素
driver.getTitle().then(function(title) {
driver.findElement(webdriver.By.xpath(...)).click();
}).thenCatch(function(e) {
driver.findElement(webdriver.By.xpath(...)).click();
});
使用具有递归函数的promise链继续尝试重新单击元素
var getStaleElement = function(selector, callback) {
var element = driver.findElement(selector);
callback(element);
}).thenCatch(function(e) {
getStaleElement(selector, callback);
});
var clickSelf = function(ele) { return ele.click() };
driver.getTitle().then(function(title) {
driver.findElement(webdriver.By.xpath(...)).click();
}).thenCatch(function(e) {
getStaleElement(webdriver.By.xpath(...), clickSelf);
});
.then()
的错误参数代替.thenCatch()
似乎Selenium无法捕获此特定错误。我使用print语句来确认.thenCatch()
捕获了其他错误,例如NoSuchElementError。是否有一种解决方法可以让我处理过时的元素?
答案 0 :(得分:0)
我遇到了类似的问题,所以我做了下面的解决方法,你可以尝试一下......
/*
* params.config - {
* opposite - {Boolean} - if true, will wait till negative result is reached/ error is thrown.
* maxWaitTime - {Number} - if this time exceeds, just throw an error and leave.
* waitTime - {Number} - wait time between two checks.
* expectValue - {Boolean} - where you just want it to run without error, or it should expect a value
* expectedValue - {Object} - object value it should or should not match.
* }
* params.fn - a function that returns a promise that we want to keep checking till desire value is reached
*/
function waiter(fn, config){
config = config || {};
var deffered = Driver.promise.defer(),
wt = config.waitTime || 100,
mwt = config.maxWaitTime || 3000,
timeoutReached = false,
pCall = function(){
fn().then(pThen, pCatch);
},
pThen = function(data){
if(timeoutReached) return;
if(config.expectValue){
if(config.opposite){
if(data == config.expectedValue){
setTimeout(pCall, wt);
}else{
clearTimeout(vTimeout);
deffered.fulfill(true);
}
}else{
if(data == config.expectedValue){
clearTimeout(vTimeout);
deffered.fulfill(true);
}else{
setTimeout(pCall, wt);
}
}
}else{
deffered.fulfill(true);
}
},
pCatch = function(err){
if(timeoutReached) return;
if(config.opposite){
deffered.fulfill(true);
}else{
setTimeout(pCall, wt);
}
};
pCall();
var vTimeout = setTimeout(function(){
timeoutReached = true;
if(config.opposite){
deffered.fulfill(true);
}else{
deffered.reject(new Error('timed-out'));
}
}, mwt);
return deffered.promise;
}
示例用法(针对您的情况):
var myPromise = function(){
return driver.findElement(webdriver.By.xpath(...)).click();
};
//default use
waiter(myPromise).then(function(){
console.log('finally...');
}).catch(fucntion(err){
console.log('not working: ', err);
});
// with custom timeout after 10 seconds
waiter(myPromise, {maxWaitTime: 10000}).then(function(){
console.log('finally...');
}).catch(fucntion(err){
console.log('not working: ', err);
});
答案 1 :(得分:0)
您对 auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.101
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.1
有正确的想法,但没有正确编码。这是有用的东西:
getStaleElement
以下是演示其用法的代码。您会发现function retryOnStale(selector, callback) {
return browser.findElement(selector).then(callback)
.thenCatch(function (err) {
if (err.name === 'StaleElementReferenceError')
return retryOnStale(selector, callback);
throw err;
});
}
包含的代码会导致陈旧的元素异常发生,并且它具有retryOnStaleIllustrate
用于诊断。然后是console.log
,它与我上面显示的相同。
retryOnStale
此示例可以执行并应生成此输出:
var webdriver = require('selenium-webdriver');
var chrome = require('selenium-webdriver/chrome');
var By = webdriver.By;
var until = webdriver.until;
var browser = new chrome.Driver();
browser.get("http://www.example.com");
function make_stale() {
browser.executeScript("document.body.innerHTML = " +
"'<p id=\\'foo\\'>foo text</p>'");
}
// Create our initial p element with id `foo`.
make_stale();
var fake_stale = 10;
// We have to use var ... = ... because later in this code we are
// going to change the value of retryOnStaleIllustrate.
function retryOnStaleIllustrate(selector, callback) {
return browser.findElement(selector).then(function (element) {
//
// This code is here to simulate a process that causes the element
// we acquired to become stale.
//
if (fake_stale) {
make_stale();
fake_stale--;
}
return callback(element);
}).thenCatch(function (err) {
if (err.name === 'StaleElementReferenceError') {
console.log("stale: retrying");
return retryOnStaleIllustrate(selector, callback);
}
throw err;
});
}
retryOnStaleIllustrate(By.id("foo"), function (element) {
element.getText().then(console.log);
});
// Once we remove the code to simulate an element becoming stale, and
// the console.log for diagnosis, this is what we are left with:
function retryOnStale(selector, callback) {
return browser.findElement(selector).then(callback)
.thenCatch(function (err) {
if (err.name === 'StaleElementReferenceError')
return retryOnStale(selector, callback);
throw err;
});
}
// This just shows that retryOnStale returns a promise which can be used.
retryOnStale(By.id("foo"), function (element) {
return element.getText();
}).then(function (text) {
console.log(text);
});
browser.quit();
所有stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
stale: retrying
foo text
foo text
行和第一个stale: retrying
都是由使用foo text
的代码生成的。最后一个retryOnStaleIllustrate
行由使用foo text
的代码生成。