【问题标题】:Using ElementArrayFinder.filter() with async/await将 ElementArrayFinder.filter() 与 async/await 一起使用
【发布时间】:2017-12-04 15:05:28
【问题描述】:

在过去的几年里,我一直在使用以下函数来过滤元素数组,并启用了 Webdriver 的控制流:

filterElementsByText (elemList, comparator, locator) {
  return elemList.filter((elem) => {
    let searchTarget = locator ? elem.element(locator) : elem
    return searchTarget.getText().then((text) => text === comparator)
  })
}

我现在正在尝试将我的 repo 迁移到使用 async/await,这需要关闭控制流。

这个转换基本上是成功的,但我在上面的函数中遇到了问题。间歇性地,我看到这个错误:

失败:java.net.ConnectException:连接被拒绝:连接

我可以使用针对 https://angularjs.org 编写的测试用例重现此问题,尽管在我自己的应用中发生的频率要高得多。

let todoList = element.all(by.repeater('todo in todoList.todos'))
let todoText = element(by.model('todoList.todoText'))
let todoSubmit = element(by.css('[value="add"]'))

let addItem = async (itemLabel = 'write first protractor test') => {
  await todoText.sendKeys(itemLabel)
  return todoSubmit.click()
}

let filterElementsByText = (elemList, comparator, locator) => {
  return elemList.filter((elem) => {
    let searchTarget = locator ? elem.element(locator) : elem
    return searchTarget.getText().then((text) => {
      console.log(`Element text is: ${text}`)
      return text === comparator
    })
  })
}

describe('filter should', () => {
  beforeAll(async () => {
    browser.ignoreSynchronization = true
    await browser.get('https://angularjs.org')

    for (let i = 0; i < 10; i++) {
      await addItem(`item${i}`)
    }
    return addItem()
  })

  it('work', async () => {
    let filteredElements = await filterElementsByText(todoList, 'write first protractor test')
    return expect(filteredElements.length).toEqual(1)
  })
})

这是在 Protractor 的 conf 文件中使用以下设置运行的:

SELENIUM_PROMISE_MANAGER: false

在简化的测试用例中,它似乎发生在 5-10% 的执行中(尽管有趣的是,它似乎确实在第一次发生时发生得更频繁)

我的问题是,这感觉像是 Webdriver 中的一个错误,但我不确定什么条件会导致该错误,所以我不确定如何继续。

【问题讨论】:

  • 如果我增加测试中创建的项目数量(我经常使用 250 个),有时感觉我可以更频繁地产生问题,但这也只是轶事
  • 如果在控制流开启时没有发生,那么可能是因为在某个地方,代码试图同时解析多个 Promise,而应该等待前一个 Promise解决。尝试在循环中编写filterElementsByText 和一些await,而不使用任何map 或filter,看看是否是这种情况。
  • 在不使用 ElementArrayFinder.filter() 的情况下编写我自己的过滤器函数似乎确实有效,并且是一个很好的解决方法,但我试图了解此错误的性质。我可以看到您描述的多重 Promise 情况实际上会在这里发生..但这如何导致“连接被拒绝”?
  • Selenium 命令打开与驱动程序的连接,发送 http 请求,然后关闭连接。所以我猜想同时执行多个命令会使连接尝试溢出驱动程序,在某些时候会回复Connection refused。
  • 经过更多的尝试,在实施这项工作后,我仍然无法重现 angularjs.org 测试用例的问题,但它实际上对我自己的应用程序没有帮助。所以 filter() 不是罪魁祸首,但我不知道实际问题是什么。

标签: node.js selenium-webdriver protractor automated-tests


【解决方案1】:

对于任何阅读和想知道的人来说,我自己的应用程序的问题是双重的。

首先,如原始问题的 cmets 中所述,ElementArrayFinder.filter() 会导致此错误,因为它对数组中的每个元素运行并行请求。

其次(在原始问题中并不明显),而不是像本测试用例中描述的那样传递 ElementArrayFinder,我实际上是在传递数组中每个元素的链式子元素,例如:

element.all(by.repeater('todo in todoList.todos').$$('span')

在发生这种情况时查看 Webdriver 输出,我注意到这会导致所有这些定位器被并行检索,从而导致相同的错误。

我可以通过这种过滤方式解决这两个问题:

let filterElementsByText = async (elemList, comparator, locator) => {
  let filteredElements = []
  let elems = await elemList
  for (let i = 0; i < elems.length; i++) {
    let elem = await elems[i]
    let searchTarget = locator ? elem.element(locator) : elem
    let text = await searchTarget.getText()
    if (text === comparator) {
      filteredElements.push(elem)
    }
  }
  return filteredElements
}

这解除了我的阻碍,但仍然感觉这些功能无法与 async/await 一起使用。

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 2019-04-15
    • 2014-06-19
    • 2018-01-14
    • 2018-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多