使用ElementArrayFinder.filter()与async/await

4

我过去几年一直使用以下函数来过滤元素数组,并启用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 的配置文件中设置的运行方式:

SELENIUM_PROMISE_MANAGER: false

使用简化测试用例似乎在5-10%的执行中出现问题(尽管,据说它在第一次出现后会更频繁地出现)
我的问题是,这感觉像是Webdriver中的一个错误,但我不确定什么条件会导致该错误,因此我不知道如何继续。

有时候感觉如果我增加测试中创建的项目数量(我经常使用250),问题就会更频繁地出现,但这只是个人经验。 - Bob B
1
如果在控制流执行时没有发生,那么很可能是因为某个地方的代码尝试同时解决多个 Promise,而应该等待前一个 Promise 解决。尝试在循环中使用一些 await 来编写 filterElementsByText,而不使用任何 mapfilter 看看是否属于这种情况。 - Florent B.
编写自己的过滤函数而不使用ElementArrayFinder.filter()似乎可以工作并且是一个好的解决方法,但我正在尝试理解这个错误的本质。我可以看到你描述的多个Promise情况实际上会发生在这里...但这如何导致“连接被拒绝”? - Bob B
2
一个Selenium命令会打开与驱动程序的连接,发送一个http请求,然后关闭连接。因此,我猜执行多个命令同时会使驱动程序被连接尝试淹没,最终会回复“连接被拒绝”。 - Florent B.
经过更多的尝试,我仍然无法在我的应用程序中实现这个解决方法并复现与angularjs.org测试用例相关的问题。因此,filter()函数不是问题的原因,但我对实际问题感到困惑。 - Bob B
1个回答

2

如果有人在阅读并且想知道,我自己的应用程序出现问题的原因有两个。

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

其次(原问题中不明显),我实际上传递了一个数组中每个元素的链接子级,例如:

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时无法使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接