I was writing pretty complicated UI tests using XCTest, and recently switched to EarlGrey, because it's so much faster and way more reliable - Tests aren't randomly failing on a build server, and the test suite could take up to a half hour to run!
One thing that I haven't been able to do in EarlGrey, that I could do in XCTest, was randomly select an element.
For example, on a calendar collectionView
, I could query for all collectionViewCell
s with 'identifier' using an NSPredicate
, and then randomly select a day using [XCUIElementQuery count]
to get an index, and then tap
.
For now, I'm going to hard code it, but I would love to randomize date selection so that I don't have to rewrite tests if we change app code.
Please let me know if I can elaborate, looking forward to solving this!
Step 1 write a matcher that can count elements matching a given matcher using GREYElementMatcherBlock
:
- (NSUInteger)elementCountMatchingMatcher:(id<GREYMatcher>)matcher {
__block NSUInteger count = 0;
GREYElementMatcherBlock *countMatcher = [GREYElementMatcherBlock matcherWithMatchesBlock:^BOOL(id element) {
if ([matcher matches:element]) {
count += 1;
}
return NO; // return NO so EarlGrey continues to search.
} descriptionBlock:^(id<GREYDescription> description) {
// Pass
}];
NSError *unused;
[[EarlGrey selectElementWithMatcher:countMatcher] assertWithMatcher:grey_notNil() error:&unused];
return count;
}
Step 2 Use %
to select a random index
NSUInteger randomIndex = arc4random() % count;
Step 3 Finally use atIndex:
to select that random element and perform action/assertion on it.
// Count all UIView's
NSUInteger count = [self elementCountMatchingMatcher:grey_kindOfClass([UIView class])];
// Find a random index.
NSUInteger randIndex = arc4random() % count;
// Tap the random UIView
[[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UIView class])]
atIndex:randIndex]
performAction:grey_tap()];