使用Nightwatch,我需要查看HTML元素列表,并在特定时间段内确定是否有任何HTML元素具有指定的消息。 (即使用mailtrap.io测试外发电子邮件 - 电子邮件可能排队等待,并且不会在5到10分钟内到达)。我有以下内容:
this.expect
.element(mailtrap.elements.messages.selector)
.text.to.contain(message)
.before(600000)

这不起作用,因为它似乎只检查执行命令时找到的第一个元素。它再次检查之前似乎没有更新它的列表。
我知道我可以clients.elements('css selector', mailtrap.elements.messages.selector, function (result) {...})
来获取一系列匹配元素并可能检查每个元素。在我开始这条道路之前,有没有更简单的方法呢?
答案 0 :(得分:0)
我解决了这个问题。首先,我创建了一个自定义命令 - waitForTextInCollection
- 模仿文档中基于示例类的命令,以及Github答案。我在这里张贴公共记录,但在自己使用之前应该进行大量审查。
我的解决方案是,我们只是想询问页面文本是否出现在元素集合中。所以使用.execute()
方法给了我一个简单的方法,而不必依赖异步例程(除了.execute)。 execute函数的结果提供给回调方法,我决定是否需要等待另一个时间间隔或者是否完成。事先,.elements()
和elementIdText()
和<{p}}使事情变得令人讨厌
Promise在这里会是一个很好的补充,但我发现较旧的回调方法和较新的promises方法之间的混合和匹配变得混乱(对于这个开发)。
我的自定义命令:
let util = require("util")
let events = require("events")
// Build the initial function prototype for our command
function waitForTextInCollection() {
events.EventEmitter.call(this)
this.startTimeInMilliseconds = null
this.checkIntervalInMilliseconds = null
}
// Inherit from the event emitter
util.inherits(waitForTextInCollection, events.EventEmitter)
// Build the actual command to be called
waitForTextInCollection.prototype.command = function(
collectionSelector,
targetText,
waitTimeout,
callback
) {
// if the waitTimeout is not specified, use the global timeout value
if (typeof waitTimeout !== "number") {
waitTimeout = this.api.globals.waitForConditionTimeout
}
// add some data to 'this' to support our work
let self = this
this.startTimeInMilliseconds = new Date().getTime()
this.checkIntervalInMilliseconds = this.api.globals.waitForConditionPollInterval
this.timeoutInMilliseconds = waitTimeout
// call the check routine and then handle any results via the callback
this.check(collectionSelector, targetText, function(result, elapsedTime) {
let message = 'waitForTextInCollection: "'
if (result) {
message += targetText + " was found (" + elapsedTime + "ms)"
} else {
message += "text NOT FOUND after " + waitTimeout + " ms"
}
self.client.assertion(result, "NOT FOUND", targetText, message, true)
// the self.emit('complete') has to be called from an async method,
// otherwise the command succeeds and then just hangs.
setTimeout(function() {
self.emit("complete")
}, 100)
})
return this
}
// The method to check if we have found the desired text yet
waitForTextInCollection.prototype.check = function( collectionSelector, desiredText, callback )
{
// determine "now" and the elapsedTime in milliseconds
let self = this
let now = new Date().getTime()
let elapsedTime = now - self.startTimeInMilliseconds
if (elapsedTime > self.timeoutInMilliseconds) {
// we've exceeded the desired timeout period, so fail the command
callback(false)
return
} else {
// define a collection of data to pass to the page
let myargs = {
selector: collectionSelector,
desiredText: desiredText
}
// ask the page itself to tell us if the text exists at this time
self.api.execute(
function(data) {
var titles = []
var elements = document.querySelectorAll(data.selector)
var found = false
elements.forEach(function(el) {
if (el.textContent == data.desiredText) {
found = true
}
})
return found
},
[myargs],
function(result) {
if (result.value) {
// Text was found
callback(true, elapsedTime)
} else {
// Text does not exist (yet) so schedule another check
setTimeout(function() {
self.check(collectionSelector, desiredText, callback)
}, self.checkIntervalInMilliseconds)
}
}
)
}
}
// Export our class
module.exports = waitForTextInCollection
&#13;
这适用于我的用例,但我并不假装它尽可能坚固。希望它可以帮助别人。