我是节点和夜间表的新手。一直在与Selenium合作多年,但我的公司已经转移到所有的节点。无论如何,在夜间观察我试图点击一个链接,而它的可见和循环,并继续点击它,直到它不是。这是我的代码的样子。任何建议将不胜感激!
"Cart Cleanup": function (browser) {
browser
.url(environment + '/ShoppingBag')
.waitForElementVisible('div.cart-top-message', 190000)
.pause(3000)
.element('class name', 'delete-form', function (visible) {
while (visible.status !== -1) {
console.log(visible.status);
browser
.useXpath() //NOW USING XPATH
.click('/html/body/div[5]/div[2]/div/div[2]/div[1]/div/div[3]/div[4]/div[2]/form[2]/input')
.useCss()
.pause(3000)
.element('class name', 'delete-form', function (visible2) {
visible = visible2
})
}
})
}
答案 0 :(得分:4)
解决此问题的最佳方法是创建自定义命令。 Nightwatch自定义命令文档:http://nightwatchjs.org/guide#writing-custom-commands
为了更容易解决这些问题,我创建了一个“waitUntil”自定义命令,它作为其他自定义命令的基础:
// WaitUntil.js, in custom commands folder specified in nightwatch.json
var util = require('util');
var events = require('events');
var TIMEOUT_RETRY_INTERVAL = 100;
function waitUntil() {
events.EventEmitter.call(this);
this.startTimeInMilliseconds = null;
}
util.inherits(waitUntil, events.EventEmitter);
/**
* The purpose of this command is to serve as a base for waitUntil_ commands. It will run the getActual function until
* the predicate funciton returns true or the timeout is reached. At that point, the assertion funciton will be called.
* @param getActual {Function} - should passe the found value to its callback. The callback will be passed as the only
* argument.
* @param predicate {Function} - the wait will end when this returns true. The actual value is passed as the only
* argument.
* @param assertion {Function} - the assertion to make. The assertion should pass when the predicate returns true. This
* function will be passed the actual value and the message.
* @param timeoutInMilliseconds {number} - the number of milliseconds to wait before timing out and failing.
* @param message {string} - the message to attach to the assertion. The elapsed time will be appended to this.
* @returns custom command waitUntil, which can be accessed as browser.waitUntil(args);
*/
waitUntil.prototype.command = function (getActual, predicate, assertion, timeoutInMilliseconds, message) {
message = message || 'waitUntil';
this.startTimeInMilliseconds = new Date().getTime();
var self = this;
this.check(getActual, predicate, function (actual, loadedTimeInMilliseconds) {
if (predicate(actual)) {
message += ': true after '
+ (loadedTimeInMilliseconds - self.startTimeInMilliseconds) + ' ms.';
} else {
message += ': timed out after ' + timeoutInMilliseconds + ' ms.';
}
assertion(actual, message);
self.emit('complete');
}, timeoutInMilliseconds);
return this;
};
waitUntil.prototype.check = function (getActual, predicate, callback, maxTimeInMilliseconds) {
var self = this;
getActual(function (result) {
// If the argument passed to the callback is an object, it is assumed that the format is of the argument passed
// to callbacks by the Nightwatch API, in which the object has a "value" attribute with the actual information.
var resultValue;
if (typeof result !== 'object') {
resultValue = result;
} else if (result.hasOwnProperty('value')) {
resultValue = result.value;
} else {
self.error('Result object does not have a value.');
return;
}
var now = new Date().getTime();
if (predicate(resultValue)) {
callback(resultValue, now);
} else if (now - self.startTimeInMilliseconds < maxTimeInMilliseconds) {
setTimeout(function () {
self.check(getActual, predicate, callback, maxTimeInMilliseconds);
}, TIMEOUT_RETRY_INTERVAL);
} else {
callback(resultValue, null);
}
});
};
module.exports = waitUntil;
使用这个模块,可以很容易地创建waitUntilTrue,waitUntilEqual等命令。您还可以创建一个“clickUntilNotVisible”命令来解决您的问题(显然,这可以与上述相结合并简化,如果这是您唯一的用例):
// clickUntilNotVisible.js, in custom commands folder specified in nightwatch.json
exports.command = function (clickElementFunction, getVisibilityFunction, assertion, timeout, message) {
var browser = this;
function clickAndGetVisiblity (callback) {
clickElementFunction();
getVisibilityFunction(callback);
}
function isTrue (actual) {
return !!actual;
}
return browser.waitUntil(clickAndGetVisiblity, isTrue, assertion, timeout, message);
};
现在我们已经定义了clickUntilNotVisible命令,我们可以解决您的问题:
function clickMyLink() {
browser
.useXpath() //NOW USING XPATH
.click('/html/body/div[5]/div[2]/div/div[2]/div[1]/div/div[3]/div[4]/div[2]/form[2]/input')
.useCss();
}
function isDeleteFormVisible(callback) {
browser
.pause(3000)
.elements('class name', 'delete-form', function (result) {
callback(result.status === 0 && result.value.length);
});
}
function verifyDeleteFormIsNotVisible (actual, message) {
browser.verify.ok(!actual, message);
}
module.exports = {
"Cart Cleanup": function (browser) {
browser
.url(environment + '/ShoppingBag')
.waitForElementVisible('div.cart-top-message', 190000)
.pause(3000)
.clickUntilNotVisible(clickMyLink, isDeleteFormVisible, verifyDeleteFormIsNotVisible, 190000);
}
};
请注意,这使用了我已经完成的工作,并且可能不是解决此问题的最有效方法,但希望它能让您了解如何自行解决问题。此外,除了waitUntil模块之外,所有这些代码都是未经测试的,因此如果没有一点调试,它可能无法工作。
答案 1 :(得分:0)
这可能会对某人有所帮助。我需要一遍又一遍地进行测试,并在此上获得成功:
const doThing = () => {
browser.pause(20000);
doThing();
};
doThing();
答案 2 :(得分:0)
在提供解决方案之前,请对您当前的代码提供一些反馈:
//input[@class="..."]
之类的东西替换它,或在输入标签中添加其他属性,因为您要获取输入标签。pause
比1000
长的时间现在,关于您的问题,要在元素可见时单击它,可以使用isVisible
方法:https://nightwatchjs.org/api/#isVisible
function clickWhileVisible(browser) {
browser.isVisible('css selector', '#your_element', ({ value }) => {
if (value === true) {
browser
.click('#your_element')
// you can increase/decrease pause if you want a pause between clicks
.pause(500);
clickWhileVisible(browser)
}
})
}
您还可以添加重试机制,以确保它不会永远运行:
function clickWhileVisible(browser, retry) {
browser.isVisible('css selector', '#your_element', ({ value }) => {
if (value === true && retry <=10) { //retries number can be modified
browser
.click('#your_element')
.pause(500);
clickWhileVisible(browser, retry+1)
}
})