代码之家  ›  专栏  ›  技术社区  ›  Hasaan Ali

在Xguitests中,如何等待两个ui元素中的任何一个存在

  •  7
  • Hasaan Ali  · 技术社区  · 8 年前

    查看XCTWaiter()。等待(…)我相信我们可以等待 多重期望 使用此代码实现

    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
    

    但这在提供的期望中使用了like和。是否有一种方法可以实现或满足所提供的期望。

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

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

    4 回复  |  直到 7 年前
        1
  •  9
  •   iwasrobbed    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
    }
    
        2
  •  1
  •   shim    5 年前

    NSPredicate 也支持或谓词。

    例如,我编写了这样的内容,以确保在开始尝试在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。空闲名称

    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。

        3
  •  0
  •   DBD    5 年前

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

    @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
    }
    
        4
  •  0
  •   N..    5 年前

    嘿,其他对我们有用的选择。我也希望帮助别人。

     XCTAssert(
                app.staticTexts["Hello Stack"]
                    .waitForExistence(timeout: 10) || app.staticTexts["Hi Stack"]
                    .waitForExistence(timeout: 10)
            )