7

看看 XCTWaiter().wait(...) 我相信我们可以使用这段代码等待多个期望变为现实

let notHittablePredicate = NSPredicate(format: "hittable == false")
let myExpectation = XCTNSPredicateExpectation(predicate: notHittablePredicate, object: element)
let result = XCTWaiter().wait(for: [myExpectation], timeout: timeout)
//for takes array of expectations

但这在提供的期望中使用了 AND。有没有办法在提供的期望中做 OR。

就像我在登录时有一个用例,在点击提交后,我想等待两个元素之一。第一个元素是“您已经在另一台设备上登录。如果您继续其他设备上的任何未保存数据将会丢失?”。第二个元素是登录后的主屏幕。所以任何人都可以出现。目前我首先等待第一个元素,直到发生超时,然后等待第二个元素。但是我想在这里优化时间并在两个元素中的任何一个存在== true 时继续前进。然后我会检查 element1 是否存在,然后点击是,然后等待主屏幕,否则只需断言 element2 的存在。

如果问题中有不清楚的地方,请发表评论。谢谢

4

4 回答 4

7

http://masilotti.com/ui-testing-tdd/启发,您不必依赖XCTWaiter. 您可以简单地运行一个循环并测试其中一个是否存在。

/// Waits for either of the two elements to exist (i.e. for scenarios where you might have
/// conditional UI logic and aren't sure which will show)
///
/// - Parameters:
///   - elementA: The first element to check for
///   - elementB: The second, or fallback, element to check for
/// - Returns: the element that existed
@discardableResult
func waitForEitherElementToExist(_ elementA: XCUIElement, _ elementB: XCUIElement) -> XCUIElement? {
    let startTime = NSDate.timeIntervalSinceReferenceDate
    while (!elementA.exists && !elementB.exists) { // while neither element exists
        if (NSDate.timeIntervalSinceReferenceDate - startTime > 5.0) {
            XCTFail("Timed out waiting for either element to exist.")
            break
        }
        sleep(1)
    }

    if elementA.exists { return elementA }
    if elementB.exists { return elementB }
    return nil
}

那么你可以这样做:

let foundElement = waitForEitherElementToExist(elementA, elementB)
if foundElement == elementA {
    // e.g. if it's a button, tap it
} else {
    // element B was found
}
于 2017-12-22T20:58:38.553 回答
1

NSPredicate也支持 OR 谓词。

例如,我写了这样的东西来确保我的应用程序在我开始尝试在 UI 测试中与之交互之前完全完成启动。这是检查应用程序中是否存在我知道在启动后每个可能的起始状态中唯一存在的各种地标。

extension XCTestCase {
  func waitForLaunchToFinish(app: XCUIApplication) {
    let loginScreenPredicate = NSPredicate { _, _ in
      app.logInButton.exists
    }

    let tabBarPredicate = NSPredicate { _, _ in
      app.tabBar.exists
    }

    let helpButtonPredicate = NSPredicate { _, _ in
      app.helpButton.exists
    }

    let predicate = NSCompoundPredicate(
      orPredicateWithSubpredicates: [
        loginScreenPredicate,
        tabBarPredicate,
        helpButtonPredicate,
      ]
    )

    let finishedLaunchingExpectation = expectation(for: predicate, evaluatedWith: nil, handler: nil)
    wait(for: [finishedLaunchingExpectation], timeout: 30)
  }
}

在测试运行时的控制台中,会重复检查我要检查的各种按钮是否存在,每次检查之间的时间是可变的。

t = 13.76s 等待 com.myapp.name 空闲

t = 18.15s 检查“我的标签栏”按钮是否存在

t = 18.88s 检查“帮助”按钮是否存在

t = 20.98s 检查“登录”按钮是否存在

t = 22.99s 检查“我的标签栏”按钮是否存在

t = 23.39s 检查“帮助”按钮是否存在

t = 26.05s 检查“登录”按钮是否存在

t = 32.51s 检查“我的标签栏”按钮是否存在

t = 16.49s 检查“登录”按钮是否存在

瞧,现在我可以同时进行,而不是单独等待每个元素。

当然,这是非常灵活的,因为您可以根据需要添加任意数量的元素,并且可以使用任何您想要的条件。如果您想要 OR 和 AND 谓词的组合,您也可以使用NSCompoundPredicate. 这可以很容易地适应一个更通用的函数,它接受一个元素数组,如下所示:

func wait(for elements: XCUIElement...) { … }

甚至可以传递一个参数来控制它是使用 OR 还是 AND。

于 2021-06-30T14:39:28.743 回答
0

拉戈曼的回答是绝对正确和伟大的。我需要等待超过 2 个可能的元素,所以我调整了他的代码以支持一个ArrayXCUIElement不是两个。

@discardableResult
func waitForAnyElement(_ elements: [XCUIElement], timeout: TimeInterval) -> XCUIElement? {
    var returnValue: XCUIElement?
    let startTime = Date()
    
    while Date().timeIntervalSince(startTime) < timeout {
        if let elementFound = elements.first(where: { $0.exists }) {
            returnValue = elementFound
            break
        }
        sleep(1)
    }
    return returnValue
}

可以像这样使用

let element1 = app.tabBars.buttons["Home"]
let element2 = app.buttons["Submit"]
let element3 = app.staticTexts["Greetings"]
foundElement = waitForAnyElement([element1, element2, element3], timeout: 5)

// do whatever checks you may want
if foundElement == element1 {
     // code
}
于 2020-12-11T17:42:01.957 回答
0

嘿,其他对我们有用的替代方案。我希望也能帮助别人。

 XCTAssert(
            app.staticTexts["Hello Stack"]
                .waitForExistence(timeout: 10) || app.staticTexts["Hi Stack"]
                .waitForExistence(timeout: 10)
        )
于 2021-07-02T16:31:27.603 回答