Nightwatch - 等待元素列表中的文本一段时间

时间:2018-03-06 00:01:33

标签: nightwatch.js

使用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) {...})来获取一系列匹配元素并可能检查每个元素。在我开始这条道路之前,有没有更简单的方法呢?

1 个答案:

答案 0 :(得分:0)

我解决了这个问题。首先,我创建了一个自定义命令 - waitForTextInCollection - 模仿文档中基于示例类的命令,以及Github答案。我在这里张贴公共记录,但在自己使用之前应该进行大量审查。

我的解决方案是,我们只是想询问页面文本是否出现在元素集合中。所以使用.execute()方法给了我一个简单的方法,而不必依赖异步例程(除了.execute)。 execute函数的结果提供给回调方法,我决定是否需要等待另一个时间间隔或者是否完成。事先,.elements()elementIdText()和<{p}}使事情变得令人讨厌

Promise在这里会是一个很好的补充,但我发现较旧的回调方法和较新的promises方法之间的混合和匹配变得混乱(对于这个开发)。

我的自定义命令:

&#13;
&#13;
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;
&#13;
&#13;

这适用于我的用例,但我并不假装它尽可能坚固。希望它可以帮助别人。