当使用并行测试同时运行所有测试时,输入文本字段是不稳定的



我正在尝试使用XCUITest进行UI测试。目前,我在向UITextField中输入文本时遇到了一些问题。以下是我在Robot类中使用键盘键入文本的内容:

func typeTextToTextField(_ element: XCUIElement, text: String, timeout: TimeInterval = timeInterval,
file: StaticString, line: UInt) {
guard assertExists(element, timeout: timeout, file: file, line: line),
element.isHittable else {
return
}
element.tap()
sleep(2)
app.activate()
element.typeText("(text)n")
sleep(2)
}

在它变成这样之前,我已经尝试过这些步骤:

  1. 只有element.tap()element.typeText()
  2. 添加了等待存在的保护(assertExists()块(
  3. 添加了sleep()以等待几秒钟键盘出现
  4. 添加了app.activate(),因为显然有时进行查询会花费太长时间。关于这个错误的答案是,我应该先调用app.activate((

如果我用并行测试同时运行所有测试,那么使用它的一些测试会工作,但有些会失败。有些将正确显示键盘并正确键入文本,而另一些将无法显示键盘并显示此错误Failed to synthesize event: Neither element nor any descendant has keyboard focus.。但当我一次运行一个测试时,它们都会是绿色的,并且工作得很完美。

所以,接下来,我尝试通过粘贴文本而不是键入文本来改变输入方式。这也不起作用。这是代码:

func pasteToTextField(_ element: XCUIElement, text: String, timeout: TimeInterval = timeInterval,
file: StaticString, line: UInt) {
app.activate()
guard assertExists(element, timeout: timeout, file: file, line: line),
element.isHittable else {
return
}
UIPasteboard.general.string = text
app.activate()
element.tap()
element.doubleTap()
element.press(forDuration: 1.2)
tap(pasteMenuItem, timeout: timeout, file: file, line: line)
sleep(5)
}

所以我做了:

  1. 只有element.tap()tap(pasteMenuItem, timeout: timeout, file: file, line: line)(与app.menuItems["Paste"].tap()相同(
  2. 添加element.doubleTap()
  3. 添加element.press()

使用粘贴功能时,有时粘贴菜单项不会显示,并出现以下错误:failed - Element: "Paste" MenuItem does not exist!。但有时效果很好。

所以,我现在无计可施了。如何将文本输入到一个文本字段中,无论是运行所有测试还是运行单个测试用例,该字段都能在所有条件下工作?

提前谢谢。

附言:它在我的CI机器上运行得很好。这很奇怪。

您可以尝试类似的

extension XCUIElement {
func clearAndEnterText(_ text: String, app: XCUIApplication) {
let currentClipboard = UIPasteboard.general.string ?? ""
waitForElementToBecomeHittable(timeout: .small)
guard let stringValue = value as? String else {
return XCTFail("Tried to clear and enter text into a non string value")
}
if stringValue == text {
return
}
if stringValue.isNotEmpty {
if app.isKeyboardKeysAvaliable(key: XCUIKeyboardKey.delete.rawValue) {
let deleteString = stringValue.map { _ in XCUIKeyboardKey.delete.rawValue }.joined()
typeText(deleteString)
} else {
let selectAllButton = app.menuItems.element(predicate: .label(Comparison.containsAny, "Select All")).firstMatch
if !selectAllButton.waitForExistence(timeout: .small) {
press(forDuration: 1.1)
}
if selectAllButton.waitForExistence(timeout: .small) {
selectAllButton.tapElement()
}
}
}
if value(forKey: "hasKeyboardFocus") as? Bool ?? false {
typeText(text)
} else {
UIPasteboard.general.string = text
let pasteButton = app.menuItems.element(predicate: .label(Comparison.containsAny, "Paste"))
if !pasteButton.waitForExistence(timeout: .small) {
tap()
press(forDuration: 2.1)
}
if pasteButton.waitForExistence(timeout: .small) {
pasteButton.tapElement()
}
}
// Dismiss tooltip if it is still displayed
if app.menuItems.element.waitForExistence(timeout: .small) {
app.tap()
}
waitForElementToBecomeHittable(timeout: .small)
UIPasteboard.general.string = currentClipboard
}
}

注意:您需要导入此文件https://github.com/ZhipingYang/Einstein/blob/600854f9b6f93bb3694deddb3fb6edbae0f67f74/Class/UITest/Model/EasyPredicate.swift,我还将名称从EasyPredicate更改为Predicate

extension XCUIApplication {
func isKeyboardKeysAvaliable(key: String) -> Bool {
let keyboard = keyboards.element(boundBy: 0)
if key.contains(all: "next") {
return keyboard.buttons[key].exists
} else {
return keyboard.keys[key].exists
}
}
}
extension XCUIElement {
@discardableResult
func waitForElementToBecomeHittable(timeout: Timeout) -> Bool {
return waitForExistence(timeout: timeout) && isHittable
}

最新更新