Using Espresso to test drawable changes

please check this tutorial I found. Seems to work pretty good https://medium.com/@dbottillo/android-ui-test-espresso-matcher-for-imageview-1a28c832626f#.4snjg8frw

Here is the summary for copy pasta ;-)

public class DrawableMatcher extends TypeSafeMatcher<View> {

    private final int expectedId;
    String resourceName;

    public DrawableMatcher(int expectedId) {
        super(View.class);
        this.expectedId = expectedId;
    }

    @Override
    protected boolean matchesSafely(View target) {
        if (!(target instanceof ImageView)){
            return false;
        }
        ImageView imageView = (ImageView) target;
        if (expectedId < 0){
            return imageView.getDrawable() == null;
        }
        Resources resources = target.getContext().getResources();
        Drawable expectedDrawable = resources.getDrawable(expectedId);
        resourceName = resources.getResourceEntryName(expectedId);

        if (expectedDrawable == null) {
            return false;
        }

        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Bitmap otherBitmap = ((BitmapDrawable) expectedDrawable).getBitmap();
        return bitmap.sameAs(otherBitmap);
    }


    @Override
    public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
            description.appendText("[");
            description.appendText(resourceName);
            description.appendText("]");
        }
    }
}

Please be aware that this only works when your Drawable is a BitmapDrawable. If you also have VectorDrawable or other Drawable you have to check for this (imageView.getDrawable() instanceOf XXXDrawable) and get the bitmap out of it. Except you have some kind of simple Drawable where you just have one color or so you can compare.

To get the Bitmap of a VectorDrawable for example you have to draw the VectorDrawable to a canvas and save it to a bitmap (I had some trouble when the VectorDrawable was tinted). If you have a StateListDrawable you can get the Drawable of the selected state and repeat your if instanceOf cascade. For other Drawable types I don't have any experience, sorry!


There is one gist which contains withBackground(), withCompoundDrawable(), withImageDrawable() matchers from Frankie Sardo. All credits to him.

And regarding image ids - you can type R.drawable.image_name, then the id of the drawable will be retrieved automatically.


Based on @wolle and @FreewheelNat's help, for comparing (Vector) Drawable:

public static Matcher<View> withDrawableId(@DrawableRes final int id) {
    return new DrawableMatcher(id);
}


public static class DrawableMatcher extends TypeSafeMatcher<View> {

    private final int expectedId;
    private String resourceName;

    public DrawableMatcher(@DrawableRes int expectedId) {
        super(View.class);
        this.expectedId = expectedId;
    }

    @Override
    protected boolean matchesSafely(View target) {
        if (!(target instanceof ImageView)) {
            return false;
        }
        ImageView imageView = (ImageView) target;
        if (expectedId < 0) {
            return imageView.getDrawable() == null;
        }
        Resources resources = target.getContext().getResources();
        Drawable expectedDrawable = resources.getDrawable(expectedId);
        resourceName = resources.getResourceEntryName(expectedId);
        if (expectedDrawable != null && expectedDrawable.getConstantState() != null) {
            return expectedDrawable.getConstantState().equals(
                    imageView.getDrawable().getConstantState()
            );
        } else {
            return false;
        }
    }


    @Override
    public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
            description.appendText("[");
            description.appendText(resourceName);
            description.appendText("]");
        }
    }
}

I prefer not to compare bitmaps and instead follow this answer's advice: https://stackoverflow.com/a/14474954/1396068

When setting the image view's drawable, also store the drawable ID in its tag with setTag(R.drawable.your_drawable). Then use Espresso's withTagValue(equalTo(R.drawable.your_drawable)) matchers to check for the correct tag.