Xcode 用户界面测试-用户界面测试失败-当点击搜索字段“取消”按钮时,无法滚动到可见(通过 AX 操作)

我试图通过点击搜索栏中的“取消”按钮来关闭搜索字段。

测试用例找不到取消按钮,它在 Xcode 7.0.1中工作正常

我添加了谓词等待按钮出现。当我们点击“取消”按钮时,测试用例失败

let button = app.buttons[“Cancel”]
let existsPredicate = NSPredicate(format: "exists == 1")


expectationForPredicate(existsPredicate, evaluatedWithObject: button, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)


button.tap() // Failing here

日志 :

    t =     7.21s     Tap SearchField
t =     7.21s         Wait for app to idle
t =     7.29s         Find the SearchField
t =     7.29s             Snapshot accessibility hierarchy for com.test.mail
t =     7.49s             Find: Descendants matching type SearchField
t =     7.49s             Find: Element at index 0
t =     7.49s             Wait for app to idle
t =     7.55s         Synthesize event
t =     7.84s         Wait for app to idle
t =     8.97s     Type 'vinayak@xmd.net' into
t =     8.97s         Wait for app to idle
t =     9.03s         Find the "Search" SearchField
t =     9.03s             Snapshot accessibility hierarchy for com.test.mail
t =     9.35s             Find: Descendants matching type SearchField
t =     9.35s             Find: Element at index 0
t =     9.36s             Wait for app to idle
t =     9.42s         Synthesize event
t =    10.37s         Wait for app to idle
t =    10.44s     Check predicate `exists == 1` against object `"Cancel" Button`
t =    10.44s         Snapshot accessibility hierarchy for com.test.mail
t =    10.58s         Find: Descendants matching type Button
t =    10.58s         Find: Elements matching predicate '"Cancel" IN identifiers'
t =    10.58s     Tap "Cancel" Button
t =    10.58s         Wait for app to idle
t =    10.64s         Find the "Cancel" Button
t =    10.64s             Snapshot accessibility hierarchy for com.test.mail
t =    10.78s             Find: Descendants matching type Button
t =    10.78s             Find: Elements matching predicate '"Cancel" IN identifiers'
t =    10.79s             Wait for app to idle
t =    11.08s         Synthesize event
t =    11.13s             Scroll element to visible
t =    11.14s             Assertion Failure: UI Testing Failure - Failed to scroll to visible (by AX action) Button 0x7f7fcaebde40: traits: 8589934593, {{353.0, 26.0}, {53.0, 30.0}}, label: 'Cancel', error: Error -25204 performing AXAction 2003
32364 次浏览

I guess here "Cancel" button returns false for hittable property, that is preventing it from tapping.

If you see tap() in documentation it says

/*!
* Sends a tap event to a hittable point computed for the element.
*/
- (void)tap;

It seems things are broken with Xcode 7.1. To keep myself (and you too ;)) unblocked from these issues I wrote an extension on XCUIElement that allows tap on an element even if it is not hittable. Following can help you.

/*Sends a tap event to a hittable/unhittable element.*/
extension XCUIElement {
func forceTapElement() {
if self.hittable {
self.tap()
}
else {
let coordinate: XCUICoordinate = self.coordinateWithNormalizedOffset(CGVectorMake(0.0, 0.0))
coordinate.tap()
}
}
}

Now you can call as

button.forceTapElement()

Update - For Swift 3 use the following:

extension XCUIElement {
func forceTapElement() {
if self.isHittable {
self.tap()
}
else {
let coordinate: XCUICoordinate = self.coordinate(withNormalizedOffset: CGVector(dx:0.0, dy:0.0))
coordinate.tap()
}
}
}

For me, the root cause was that the objects I wanted to tap

  • have been set to hidden (and back)
  • have been removed and re-attached

In both cases the isAccessibilityElement property was false afterwards. Setting it back to true fixed it.

Please check the trait of the element, i was facing the same issue with TableViewSectionHeader, i was trying to tap but it was failing at every point

enter image description here

In my case it was having a programmatically added UI element covering the button.

If you're using the AppCenter simulator to run the tests, you should make sure that you're running the tests on the same device version than your local simulator. I lost 3 days of work because of this.

This question ranks well for Google queries around the term "Failed to scroll to visible (by AX action) Button". Given the age of the question I was inclined to think this was no longer an issue with the XCUITest framework as the accepted answer suggests.

I found this issue was due to the XCElement existing, but being hidden behind the software keyboard. The error is emitted by the framework since it is unable to scroll a view that exists into view to be tappable. In my case the button in question was behind the software keyboard sometimes.

I found the iOS Simulator's software keyboard may be toggled off in some cases (eg: on your machine) and toggled on in others (eg: on your CI). In my case I had toggled the software keyboard off on one machine, and by default it was toggled on on others.

Solution: Dismiss the keyboard before attempting to tap buttons that may be behind it.

I found tapping somewhere that explicitly dismissed the keyboard before tapping on the button solved my problem in all environments.

I added add some actions to get the current responder to resignFirstResponder. The views behind my text views will force the first responder to resign, so I tap somewhere just underneath the last text area.

 /// The keyboard may be up, dismiss it by tapping just below the password field
let pointBelowPassword = passwordSecureTextField.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 1))
pointBelowPassword.press(forDuration: 0.1)

The workaround of Sandy seemed help for a while but then no more - I then changed it like this:

func waitAndForceTap(timeout: UInt32 = 5000) {
XCTAssert(waitForElement(timeout: timeout))
coordinate(withNormalizedOffset: CGVector(dx:0.5, dy:0.5)).tap()
}

Main point being that as the issue is that isHittable check throws an exception, I don't do this check at all and go straight for coordinates after the element is found.

In the spirit of things that can cover your element, I had the RN debugger partially overlayed on top of my icon:

enter image description here

Try this:

if !button.isHittable {
let coordinate: XCUICoordinate = button.coordinate(withNormalizedOffset: CGVector(dx:0.0, dy:0.0))
coordinate.tap()
}