我有一个带有地址簿部分的帐户页面。 我进行了一些测试,例如创建和更新地址,然后在小黄瓜中,我在末尾有以下命令:
And I delete all the addresses
在common-steps.js中,我有:
Then(/^I delete all the addresses$/,function(){
return client.addressBookCleaner();
})
该功能已经存在,我正在尝试弄清楚其工作原理:基本上它可以递归运行并删除所有地址:
var addressBookCleaner = function () {
function clickMyLink() {
this
.click('[data-ctrl="addressbook.removeButton"]')
.waitForElementVisible('[data-action="confirm"]', 190000)
.pause(500)
.click('[data-action="confirm"]')
.waitForElementVisible('.uiLayer-removeButton .mfp-close', 190000)
.pause(500)
.click('.uiLayer-removeButton .mfp-close')
.pause(500);
}
function isDeleteFormVisible(callback) {
this
.pause(1000)
.isVisible('[data-ctrl="addressbook.removeButton"]', function (result) {
callback(result.status === 0 && result.value.length);
});
}
function verifyDeleteFormIsNotVisible(actual, message) {
this.verify.ok(!actual, message);
}
this
.waitForElementVisible('body', 190000)
.pause(1000)
.clickUntilNotVisible(clickMyLink.bind(this), isDeleteFormVisible.bind(this), verifyDeleteFormIsNotVisible.bind(this), 190000);
};
exports.command = function () {
debugger;
addressBookCleaner.call(this);
};
如您所见,调用的函数为clickUntilNotVisible
:
exports.command = function (clickElementFunction, getVisibilityFunction, assertion, timeout, message) {
function clickAndGetVisiblity (callback) {
//debugger;
clickElementFunction();
getVisibilityFunction(callback);
}
function isTrue (actual) {
return !!actual;
}
return this.waitUntil(clickAndGetVisiblity, isTrue, assertion, timeout, message);
};
调用waitUntil函数:
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;
我无法完全理解它的工作原理,基本上它是递归工作,删除所有地址,然后给我一个错误(因为我想,它找不到任何地址):所以我必须修改该函数以停止它。
我以这种方式修改了addressBookCleaner模块的功能之一:
function isDeleteFormVisible(callback) {
var self = this;
this
.pause(1000)
.element('css selector', '[data-ytos-ctrl="addressbook.removeButton"]', function (result) {
if(result.status === -1){
return self.pause(4000)
.verify.attributeContains('[data-ctrl="addressbook.addressesCount"]','data-address-count','0')
} else {
callback(result.status === 0 && result.value.length);
}
});
}
这没有给我任何错误,但是测试根本没有结束,我在控制台中看到以下消息:
√ Testing if attribute data-address-count of <[data-ctrl="addressbook.addressesCount"]> contains "0".
如果我将值从0修改为另一个数字,则会收到错误消息,并且测试失败,但是如果正确无误。
如果我在验证后附加end()函数,浏览器将关闭,但不会收到任何“测试通过”消息