UI Tests中如何实现元素按下、截图再释放的操作?
解决UITest中按压元素时截图的问题
你的问题出在press(forDuration:)的执行逻辑上——这个方法是先完成整个按压+释放的动作后,才会执行后续的代码,所以你现在的截图是在元素被松开后才触发的,自然看不到按压状态下的界面。
要实现「按住元素 → 截图 → 释放」的流程,我们需要把按压操作和截图操作异步拆分,确保截图发生在按压持续的过程中。以下是具体的实现方案:
步骤1:优化元素定位(可选但强烈推荐)
首先,尽量避免用多层嵌套的children(matching:)来定位元素,这种写法非常脆弱,UI层级稍有变动就会失效。建议在App的代码中给目标元素设置可访问性标识符:
// App端代码(比如UIViewController里) yourTargetElement.accessibilityIdentifier = "EffectsPressTarget"
然后在UITest中直接通过标识符获取元素:
let targetElement = app.otherElements["EffectsPressTarget"]
步骤2:实现按压中截图的逻辑
核心思路是异步启动按压操作,等按压生效后立刻截图,最后等待按压完成释放元素:
// 获取目标元素(如果用了accessibilityIdentifier就用上面的写法) let targetElement = app.children(matching: .window) .element(boundBy: 0) .children(matching: .other) .element .children(matching: .other) .element(boundBy: 1) .children(matching: .other) .element(boundBy: 3) // 获取元素的中心坐标(确保按压位置准确) let elementCoordinate = targetElement.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)) // 异步启动按压,设置足够长的持续时间(比如2秒,给截图留足时间) DispatchQueue.global().async { elementCoordinate.press(forDuration: 2.0) } // 短暂等待(0.2秒左右),确保按压已经触发并显示出按压状态的UI Thread.sleep(forTimeInterval: 0.2) // 执行截图,这时候元素处于被按住的状态 snapshot("EffectsScreenshot") // 等待按压操作完成(剩下的1.8秒),元素会自动释放 Thread.sleep(forTimeInterval: 1.8)
为什么这个方案可行?
DispatchQueue.global().async把按压操作放到后台队列执行,不会阻塞主线程的截图逻辑- 短暂的
Thread.sleep是为了确保系统已经处理了按压事件,界面显示出按压状态(比如高亮、弹出菜单等) - 最后等待按压完成,元素会自动释放,符合你想要的完整流程
如果你觉得Thread.sleep不够优雅,也可以用XCTWaiter配合预期条件来代替,比如等待元素的按压状态出现,但对于简单的场景,Thread.sleep已经足够好用。
内容的提问来源于stack exchange,提问作者Grant Emerson
相关产品推荐
相关产品推荐

