Search code examples
iostestingfunctional-testingearlgrey

EarlGrey - How do I check if multiple objects are being shown on the screen


The EarlGrey documentation says that

You must narrow down the selection until it can uniquely identify a single UI element

I have three UIViews on my UI that I need to check the visibility of using the grey_sufficientlyVisible() assertion. However, unless if I literally pick each one up using their individual accessibility labels or so, I cannot match all of them. Is there a way to match a super-set of views or should I create individual test conditions for each of the views?


Solution

  • By saying that matchers must be able to uniquely identify an element, EarlGrey is making it harder to do the wrong thing. Imagine unintentionally selecting the wrong element when multiple elements are matched and asserting if it's visible and later finding out the wrong element was checked for visibility...yikes!

    Anyhow, what you're trying to accomplish can be done in a couple of ways:

    1) If all of these views share a common parent then you could write a custom matcher that matches on the parent and write a custom assertion that iterates over the subviews, storing the view that have the desired accessibility labels and then runs each of those individual views through visibility matcher. Something like:

    for (UIView *view in matchedViews) {
      GREYAssertTrue([grey_sufficientlyVisible() matches:view],
                     @"View %@ is not visible", view);
    }
    

    2) Or if you don't mind creating a little more sophisticated technique of matching multiple views that you can probably create a reusable function out of, you can do something similar to what I had done for a test which checked if a table view has five rows with accessibility label "Row 1":

    - (void)testThereAreThreeViewsWithRow1AsAccessibilityLabel {
      NSMutableArray *evaluatedElements = [[NSMutableArray alloc] init];
      __block bool considerForEvaluation = NO;
      MatchesBlock matchesBlock = ^BOOL(UIView *view) {
        if (considerForEvaluation) {
          if (![evaluatedElements containsObject:view]) {
            [evaluatedElements addObject:view];
            considerForEvaluation = NO;
            return YES;
          }
        }
        return NO;
      };
      DescribeToBlock describeToBlock = ^void(id<GREYDescription> description) {
        [description appendText:@"not in matched list"];
      };
      id<GREYMatcher> notAlreadyEvaluatedListMatcher =
          [GREYElementMatcherBlock matcherWithMatchesBlock:matchesBlock
                                          descriptionBlock:describeToBlock];
      id<GREYMatcher> viewMatcher =
          grey_allOf(grey_accessibilityLabel(@"Row 1"), notAlreadyEvaluatedListMatcher, nil);
      for (int i = 0; i < 5; i++) {
        considerForEvaluation = YES;
        [[EarlGrey selectElementWithMatcher:viewMatcher] assertWithMatcher:grey_sufficientlyVisible()];
      }
    }