public final class

PositionAssertions

extends java.lang.Object

 java.lang.Object

↳androidx.test.espresso.assertion.PositionAssertions

Gradle dependencies

compile group: 'androidx.test.espresso', name: 'espresso-core', version: '3.5.0-alpha06'

  • groupId: androidx.test.espresso
  • artifactId: espresso-core
  • version: 3.5.0-alpha06

Artifact androidx.test.espresso:espresso-core:3.5.0-alpha06 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.test.espresso:espresso-core com.android.support.test.espresso:espresso-core

Androidx class mapping:

androidx.test.espresso.assertion.PositionAssertions android.support.test.espresso.assertion.PositionAssertions

Overview

A collection of ViewAssertions for checking relative position of elements on the screen.

These comparisons are on the x,y plane; they ignore the z plane.

Summary

Methods
public static ViewAssertionisAbove(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely above the view matching the given matcher.

public static ViewAssertionisBelow(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely below the view matching the given matcher.

public static ViewAssertionisBottomAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is bottom aligned with the view matching the given matcher.

public static ViewAssertionisCompletelyAbove(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely above the view matching the given matcher.

public static ViewAssertionisCompletelyBelow(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely below the view matching the given matcher.

public static ViewAssertionisCompletelyLeftOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely left of the view matching the given matcher.

public static ViewAssertionisCompletelyRightOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely right of the view matching the given matcher.

public static ViewAssertionisLeftAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is left aligned with the view matching the given matcher.

public static ViewAssertionisLeftOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely left of the view matching the given matcher.

public static ViewAssertionisPartiallyAbove(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially above the view matching the given matcher.

public static ViewAssertionisPartiallyBelow(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially below the view matching the given matcher.

public static ViewAssertionisPartiallyLeftOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially left of the view matching the given matcher.

public static ViewAssertionisPartiallyRightOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially right of the view matching the given matcher.

public static ViewAssertionisRightAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is right aligned with the view matching the given matcher.

public static ViewAssertionisRightOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely right of the view matching the given matcher.

public static ViewAssertionisTopAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is top aligned with the view matching the given matcher.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static ViewAssertion isCompletelyLeftOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely left of the view matching the given matcher.

public static ViewAssertion isCompletelyRightOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely right of the view matching the given matcher.

public static ViewAssertion isLeftOf(<any> matcher)

Deprecated: Use PositionAssertions instead.

Returns a ViewAssertion that asserts that view displayed is completely left of the view matching the given matcher.

public static ViewAssertion isRightOf(<any> matcher)

Deprecated: Use PositionAssertions instead.

Returns a ViewAssertion that asserts that view displayed is completely right of the view matching the given matcher.

public static ViewAssertion isPartiallyLeftOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially left of the view matching the given matcher.

public static ViewAssertion isPartiallyRightOf(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially right of the view matching the given matcher.

public static ViewAssertion isLeftAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is left aligned with the view matching the given matcher.

The left 'x' coordinate of the view displayed must equal the left 'x' coordinate of the view matching the given matcher.

public static ViewAssertion isRightAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is right aligned with the view matching the given matcher.

The right 'x' coordinate of the view displayed must equal the right 'x' coordinate of the view matching the given matcher.

public static ViewAssertion isCompletelyAbove(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely above the view matching the given matcher.

public static ViewAssertion isCompletelyBelow(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is completely below the view matching the given matcher.

public static ViewAssertion isPartiallyAbove(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially above the view matching the given matcher.

public static ViewAssertion isPartiallyBelow(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is partially below the view matching the given matcher.

public static ViewAssertion isAbove(<any> matcher)

Deprecated: Use PositionAssertions instead.

Returns a ViewAssertion that asserts that view displayed is completely above the view matching the given matcher.

public static ViewAssertion isBelow(<any> matcher)

Deprecated: Use PositionAssertions instead.

Returns a ViewAssertion that asserts that view displayed is completely below the view matching the given matcher.

public static ViewAssertion isBottomAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is bottom aligned with the view matching the given matcher.

The bottom 'y' coordinate of the view displayed must equal the bottom 'y' coordinate of the view matching the given matcher.

public static ViewAssertion isTopAlignedWith(<any> matcher)

Returns a ViewAssertion that asserts that view displayed is top aligned with the view matching the given matcher.

The top 'y' coordinate of the view displayed must equal the top 'y' coordinate of the view matching the given matcher.

Source

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.test.espresso.assertion;

import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
import static androidx.test.espresso.util.TreeIterables.breadthFirstViewTraversal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.hamcrest.Matchers.is;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import androidx.test.espresso.AmbiguousViewMatcherException;
import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.ViewAssertion;
import androidx.test.espresso.util.HumanReadables;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import java.util.Iterator;
import java.util.Locale;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;

/**
 * A collection of {@link ViewAssertion}s for checking relative position of elements on the screen.
 *
 * <p>These comparisons are on the x,y plane; they ignore the z plane.
 */
public final class PositionAssertions {

  private static final String TAG = "PositionAssertions";

  private PositionAssertions() {}

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely left of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isCompletelyLeftOf(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.COMPLETELY_LEFT_OF);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely right of the
   * view matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isCompletelyRightOf(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.COMPLETELY_RIGHT_OF);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely left of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   * @deprecated Use {@link #isCompletelyLeftOf(Matcher)} instead.
   */
  @Deprecated
  public static ViewAssertion isLeftOf(Matcher<View> matcher) {
    return isCompletelyLeftOf(matcher);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely right of the
   * view matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   * @deprecated Use {@link #isCompletelyRightOf(Matcher)} instead.
   */
  @Deprecated
  public static ViewAssertion isRightOf(Matcher<View> matcher) {
    return isCompletelyRightOf(matcher);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is partially left of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is no horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isPartiallyLeftOf(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.PARTIALLY_LEFT_OF);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is partially right of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is no horizontal overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isPartiallyRightOf(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.PARTIALLY_RIGHT_OF);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is left aligned with the view
   * matching the given matcher.
   *
   * <p>The left 'x' coordinate of the view displayed must equal the left 'x' coordinate of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if the views are not aligned to the left.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isLeftAlignedWith(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.LEFT_ALIGNED);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is right aligned with the view
   * matching the given matcher.
   *
   * <p>The right 'x' coordinate of the view displayed must equal the right 'x' coordinate of the
   * view matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if the views are not aligned to the right.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isRightAlignedWith(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.RIGHT_ALIGNED);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely above the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isCompletelyAbove(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.COMPLETELY_ABOVE);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely below the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isCompletelyBelow(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.COMPLETELY_BELOW);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is partially above the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is no vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isPartiallyAbove(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.PARTIALLY_ABOVE);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is partially below the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is no vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isPartiallyBelow(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.PARTIALLY_BELOW);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely above the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there is any vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   * @deprecated Use {@link #isCompletelyAbove(Matcher)} instead.
   */
  @Deprecated
  public static ViewAssertion isAbove(Matcher<View> matcher) {
    return isCompletelyAbove(matcher);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is completely below the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if there any vertical overlap.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   * @deprecated Use {@link #isCompletelyBelow(Matcher)} instead.
   */
  @Deprecated
  public static ViewAssertion isBelow(Matcher<View> matcher) {
    return isCompletelyBelow(matcher);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is bottom aligned with the
   * view matching the given matcher.
   *
   * <p>The bottom 'y' coordinate of the view displayed must equal the bottom 'y' coordinate of the
   * view matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if the views are not aligned bottom.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isBottomAlignedWith(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.BOTTOM_ALIGNED);
  }

  /**
   * Returns a {@link ViewAssertion} that asserts that view displayed is top aligned with the view
   * matching the given matcher.
   *
   * <p>The top 'y' coordinate of the view displayed must equal the top 'y' coordinate of the view
   * matching the given matcher.
   *
   * @throws junit.framework.AssertionFailedError if the views are not aligned top.
   * @throws AmbiguousViewMatcherException if more than one view matches the given matcher.
   * @throws NoMatchingViewException if no views match the given matcher.
   */
  public static ViewAssertion isTopAlignedWith(Matcher<View> matcher) {
    return relativePositionOf(matcher, Position.TOP_ALIGNED);
  }

  static ViewAssertion relativePositionOf(
      final Matcher<View> viewMatcher, final Position position) {
    checkNotNull(viewMatcher);
    return new ViewAssertion() {
      @Override
      public void check(final View foundView, NoMatchingViewException noViewException) {
        StringDescription description = new StringDescription();
        if (noViewException != null) {
          description.appendText(
              String.format(
                  Locale.ROOT,
                  "' check could not be performed because view '%s' was not found.\n",
                  noViewException.getViewMatcherDescription()));
          Log.e(TAG, description.toString());
          throw noViewException;
        } else {
          // TODO: describe the foundView matcher instead of the foundView itself.
          description
              .appendText("View:")
              .appendText(HumanReadables.describe(foundView))
              .appendText(" is not ")
              .appendText(position.toString())
              .appendText(" view ")
              .appendText(viewMatcher.toString());
          assertThat(
              description.toString(),
              isRelativePosition(
                  foundView, findView(viewMatcher, getTopViewGroup(foundView)), position),
              is(true));
        }
      }
    };
  }

  // Helper methods
  static View findView(final Matcher<View> toView, View root) {
    Preconditions.checkNotNull(toView);
    Preconditions.checkNotNull(root);
    final Predicate<View> viewPredicate =
        new Predicate<View>() {
          @Override
          public boolean apply(View input) {
            return toView.matches(input);
          }
        };
    Iterator<View> matchedViewIterator =
        Iterables.filter(breadthFirstViewTraversal(root), viewPredicate).iterator();
    View matchedView = null;
    while (matchedViewIterator.hasNext()) {
      if (matchedView != null) {
        // Ambiguous!
        throw new AmbiguousViewMatcherException.Builder()
            .withRootView(root)
            .withViewMatcher(toView)
            .withView1(matchedView)
            .withView2(matchedViewIterator.next())
            .withOtherAmbiguousViews(Iterators.toArray(matchedViewIterator, View.class))
            .build();
      } else {
        matchedView = matchedViewIterator.next();
      }
    }
    if (matchedView == null) {
      throw new NoMatchingViewException.Builder()
          .withViewMatcher(toView)
          .withRootView(root)
          .build();
    }
    return matchedView;
  }

  private static ViewGroup getTopViewGroup(View view) {
    ViewParent currentParent = view.getParent();
    ViewGroup topView = null;
    while (currentParent != null) {
      if (currentParent instanceof ViewGroup) {
        topView = (ViewGroup) currentParent;
      }
      currentParent = currentParent.getParent();
    }
    return topView;
  }

  static boolean isRelativePosition(View view1, View view2, Position position) {
    int[] location1 = new int[2];
    int[] location2 = new int[2];
    view1.getLocationOnScreen(location1);
    view2.getLocationOnScreen(location2);

    switch (position) {
      case COMPLETELY_LEFT_OF:
        return location1[0] + view1.getWidth() <= location2[0];
      case COMPLETELY_RIGHT_OF:
        return location2[0] + view2.getWidth() <= location1[0];
      case COMPLETELY_ABOVE:
        return location1[1] + view1.getHeight() <= location2[1];
      case COMPLETELY_BELOW:
        return location2[1] + view2.getHeight() <= location1[1];
      case PARTIALLY_LEFT_OF:
        return location1[0] < location2[0] && location2[0] < location1[0] + view1.getWidth();
      case PARTIALLY_RIGHT_OF:
        return location2[0] < location1[0] && location1[0] < location2[0] + view2.getWidth();
      case PARTIALLY_ABOVE:
        return location1[1] < location2[1] && location2[1] < location1[1] + view1.getHeight();
      case PARTIALLY_BELOW:
        return location2[1] < location1[1] && location1[1] < location2[1] + view2.getHeight();
      case LEFT_ALIGNED:
        return location1[0] == location2[0];
      case RIGHT_ALIGNED:
        return location1[0] + view1.getWidth() == location2[0] + view2.getWidth();
      case TOP_ALIGNED:
        return location1[1] == location2[1];
      case BOTTOM_ALIGNED:
        return location1[1] + view1.getHeight() == location2[1] + view2.getHeight();
      default:
        return false;
    }
  }

  enum Position {
    COMPLETELY_LEFT_OF("completely left of"),
    COMPLETELY_RIGHT_OF("completely right of"),
    COMPLETELY_ABOVE("completely above"),
    COMPLETELY_BELOW("completely below"),
    PARTIALLY_LEFT_OF("partially left of"),
    PARTIALLY_RIGHT_OF("partially right of"),
    PARTIALLY_ABOVE("partially above"),
    PARTIALLY_BELOW("partially below"),
    LEFT_ALIGNED("aligned left with"),
    RIGHT_ALIGNED("aligned right with"),
    TOP_ALIGNED("aligned top with"),
    BOTTOM_ALIGNED("aligned bottom with");

    private final String positionValue;

    private Position(String value) {
      positionValue = value;
    }

    @Override
    public String toString() {
      return positionValue;
    }
  }
}