8

I'm writing a UIAutomation test case and I need to wait for the user to be activated before continuing. There doesn't seem to be a nice way to check for a button to change to the enabled state.

Whats the best was to wait for something to happen in the UI before checking it's status?

Neither dispatch_after nor NSTimer seem to work. They just block then fail.

Senseful
  • 86,719
  • 67
  • 308
  • 465
Brian
  • 772
  • 1
  • 13
  • 31

4 Answers4

17

It's actually pretty easy if you use NSPredicates and expectations. You can even set a timeout value. This example shows you how to do it with a 5 second timeout.

let exists = NSPredicate(format:"enabled == true")
expectationForPredicate(exists, evaluatedWithObject: app.tables.textFields["MY_FIELD_NAME"], handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
Etienne
  • 1,197
  • 10
  • 19
0

The better way to wait and check an element isn't the delay() function, but the pushTimeout() one. Apple recommends to use the second function. Here is a code sample:

UIATarget.localTarget().pushTimeout(10)
button.tap()
UIATarget.localTarget().popTimeout()

Apple will repeatedly try to tap the button and will wait up to 10 seconds. Here's a link to the documentation.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
emoleumassi
  • 4,881
  • 13
  • 67
  • 93
0

Etienne's answer is correct but in my scenario it required something extra.

I'm using React Native and had a <TouchableWithoutFeedback disabled={true}> component. However I could see that whenever XCUI tried to check its state it considered it enabled. Indeed, using a breakpoint and checking element.IsEnabled clearly contradicted what I was seeing in the UI.

Using AccessibilityState will achieve this however, for example:

<TouchableWithoutFeedback
   accessibilityState={{
      disabled: this.props.disabled,
   }}
>

Experienced with RN 0.62.2

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
-4

You should be able to implement a while loop to check for the condition you want (e.g. button enabled). That will stop the test case progress until the while condition is met and the tests will continue. Build in a delay to slow polling and make sure you have a timeout so you don't get stuck indefinitely.

Pseudocode:

While (/*button is disabled*/) {
    if (/*timeout condition met*/) {
        /*handle error*/
        break;
    }

    UIATarget.delay(<duration in seconds>);
}
Murdock
  • 826
  • 9
  • 21
  • Thanks! I did't know about the delay function. – Brian Jul 08 '15 at 18:35
  • Hmm actually I can't find UITarget.delay anywhere. – Brian Jul 08 '15 at 18:46
  • Sorry it's UIATarget. Corrected in answer. https://developer.apple.com/library/ios/documentation/ToolsLanguages/Reference/UIATargetClassReference/#//apple_ref/javascript/instm/UIATarget/delay – Murdock Jul 08 '15 at 19:02
  • @Zaph0d42 If you found my answer efficient and helpful, please select it as your accepted answer. Thanks! – Murdock Jul 10 '15 at 20:11
  • Hey Murdock. Thanks for the help. UIATarget is part of the Javascript UITesting from Xcode 6. I should have made it clear that I was using the new UIAutomation that is part of the XCTest framework in Xcode 7. There isn't a delay function there AFAICT. So I don't think that it's the correct answer. – Brian Jul 10 '15 at 21:04
  • This is a very manual way of doing it. You can actually do it using build in features. See NSPredecate and look up for Expectations work. – Etienne Oct 16 '15 at 00:37