Espresso NestedScrollView scrolling via Kotlin Delegation

Anthony Sierra
Aug 22, 2018 · 2 min read

A problem I ran across the other day was how to properly scroll a NestedScrollView in an Espresso test. The problem comes from an issue with the Android framework’s ScrollToAction class for Espresso. Which can be found here. The below code snippet shows the problem in that class.

public Matcher<View> getConstraints() {    
return allOf(withEffectiveVisibility(Visibility.VISIBLE),
isDescendantOfA(anyOf(
isAssignableFrom(ScrollView.class),
isAssignableFrom(HorizontalScrollView.class),
isAssignableFrom(ListView.class))));
}

The method getConstraints is called which is then used to say what types of elements are supported for scrolling. As we can see from above NestedScrollView is not one of them.

So when in your Espresso tests, code like this is written.

onView(withId(R.id.item_on_nested_scroll_view)).perform(scrollTo())

It will not work, instead you are given a fancy exception like below. Saying something along the lines of could not find suitable view given constraints. Which as we can see here, the constraints are indeed not what we want.

java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints:
(view has effective visibility=VISIBLE and is descendant of a: (is assignable from class: class android.widget.ScrollView or is assignable from class: class android.widget.HorizontalScrollView or is assignable from class: class android.widget.ListView))

In the Java days, the alternative would have been to copy this class into your project and alter the getConstraints method. This however is usually not great. Since Android can change, as well as Espresso, we would have to maintain this class.

What we really care about is just this one getConstraints method class and altering its return value. We also do not want to worry about maintenance of this class or any possibly bugs or changes that could be added to it as time progresses.

Delegation with Kotlin

Instead of copying the file into our project we have this new ability to use Delegation in Kotlin. This wonderful ability will allow us to only focus on what we need to change. The below code is what we can use instead.

As you can see we create a class which takes in an object to delegate any method calls we do not override to. Next we override the only method we care about (getConstraints). Once that is overriden we add to the list of allowed items a NestedScrollView. For convenience we also add a default value to the delegate object of scrollTo. This is nice as it allows us to use the below code for scrolling.

onView(withId(R.id.item_on_nested_scroll_view).perform(NestedScrollViewExtension())

Which will then scroll to our item in our nested scroll view. One downside of this approach is that we still need to take into account any business logic of the getConstraint method. The upside of this though is that is the only logic we need to take into account.

Hopefully this helps you with scrolling in the future and thanks for reading.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade