UIAutomation and XCTestCase: how to wait for button activation

I am writing a UIAutomation test case and I need to wait for the user to be activated before proceeding. There seems to be no good way to check that the button changes to an on state.

Was it better to wait for something in the UI before checking its status?

It seems that dispatcher_after and NSTimer are not working. They just block and then fail.

+3


source to share


4 answers


It's actually pretty easy if you use NSPredicates and expectations. You can even set a timeout value. This example shows how to do this 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)

      

+5


source


The best way to wait and check an element is not a function delay()

, but pushTimeout()

. Apple recommends using the second feature. Here's some sample code:

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

      



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

+1


source


Murdoch's answer is for the old JavaScript testing framework. I eventually came up with this:

https://gist.github.com/briandw/59bf5a06afe8af67a690

- (void)waitFor:(NSTimeInterval)seconds withExpectationBlock:(BOOL (^)())block
{
    NSDate *timeoutDate = [[NSDate alloc] initWithTimeIntervalSinceNow:seconds];

    while (YES)
    {
        if ([timeoutDate timeIntervalSinceNow] < 0 || !block())
        {
            return;
        }

        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    }
}

XCUIElement *nextButton = app.navigationBars[@"Title"].buttons[@"Next"];
XCTestExpectation *activationExpectation = [self expectationWithDescription:@"Waiting"];
[self waitFor:20.0 withExpectationBlock:^BOOL()
 {
     if (nextButton.exists && nextButton.enabled)
     {
         [activationExpectation fulfill];
         return YES;
     }

     return NO;
 }];

      

-1


source


You should be able to implement a while loop to check for the state you want (the button is enabled, for example). This will pause the test run until the condition is met and the tests continue. Build a delay for 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>);
}

      

-2


source







All Articles