在我目前的公司,我们的做法是创建一个 XCUIElement 表达式期望(以创建一个通用的等待方法)。我们通过以下方式来确保它是可维护的(很多期望的变化,并且不想创建很多方法/特定的谓词来做到这一点。
斯威夫特 5
基础方法
表达式用于形成动态谓词值。我们可以从谓词创建XCTNSPredicateExpectation,然后将其传递给XCTWaiter 以显式等待。如果结果不是completed,那么我们将失败并显示可选消息。
@discardableResult
func wait(
until expression: @escaping (XCUIElement) -> Bool,
timeout: TimeInterval = 15,
message: @autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) -> Self {
if expression(self) {
return self
}
let predicate = NSPredicate { _, _ in
expression(self)
}
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: nil)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
if result != .completed {
XCTFail(
message().isEmpty ? "expectation not matched after waiting" : message(),
file: file,
line: line
)
}
return self
}
用法
app.buttons["my_button"].wait(until: { $0.exists })
app.buttons["my_button"].wait(until: { $0.isHittable })
键路径
然后我们将其包装在一个方法中,其中 keyPath 和 match 值构成表达式。
@discardableResult
func wait<Value: Equatable>(
until keyPath: KeyPath<XCUIElement, Value>,
matches match: Value,
timeout: TimeInterval = 15,
message: @autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) -> Self {
wait(
until: { $0[keyPath: keyPath] == match },
timeout: timeout,
message: message,
file: file,
line: line
)
}
用法
app.buttons["my_button"].wait(until: \.exists, matches: true)
app.buttons["my_button"].wait(until: \.isHittable, matches: false)
然后您可以包装该方法,其中match 值始终为true,这是我发现最常见的用例。
用法
app.buttons["my_button"].wait(until: \.exists)
app.buttons["my_button"].wait(until: \.isHittable)
我写了一篇关于它的帖子,并在那里获得了完整的扩展文件:https://sourcediving.com/clean-waiting-in-xcuitest-43bab495230f