I am trying to test EditTexts in my form that are within a NestedScrollView. I am running the following code:
onView(withId(R.id.register_scroll_view)).perform(scrollTo()).perform(click());
where register_scroll_view is my NestedScrollView. However, I am getting an exception:
android.support.test.espresso.PerformException: Error performing 'scroll to' on view 'with id: com.eazyigz.myapp:id/register_scroll_view'. Caused by: 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))
How do I properly devise this test so that I can test my EditTexts which need to be scrolled to to become visible?
androidx.core.widget.NestedScrollView. NestedScrollView is just like ScrollView , but it supports acting as both a nested scrolling parent and child on both new and old versions of Android. Nested scrolling is enabled by default.
4 Answers. Show activity on this post. You can use SWIPE to scroll to the bottom of the screen: Espresso.
I have written single ViewAction for handling scroll to views that are children of NestedScrollView. It also takes into account that CoordinatorLayout might be a root - so you don't need to be afraid of toolbar changing it's size.
There is some code. You need to copy paste this class to your project somewhere. And then you can use it for example like that:
onView(withId(R.id.register_scroll_view))
.perform(CustomScrollActions.nestedScrollTo, click());
Important: it is not a replacement for scrollTo()
it is another scrolling ViewAction that you should use instead in cases when you deal with NestedScrollView.
So there is a ViewAction I was talking about:
public class CustomScrollActions {
public static ViewAction nestedScrollTo() {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return Matchers.allOf(
isDescendantOfA(isAssignableFrom(NestedScrollView.class)),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE));
}
@Override
public String getDescription() {
return "Find parent with type " + NestedScrollView.class +
" of matched view and programmatically scroll to it.";
}
@Override
public void perform(UiController uiController, View view) {
try {
NestedScrollView nestedScrollView = (NestedScrollView)
findFirstParentLayoutOfClass(view, NestedScrollView.class);
if (nestedScrollView != null) {
CoordinatorLayout coordinatorLayout =
(CoordinatorLayout) findFirstParentLayoutOfClass(view, CoordinatorLayout.class);
if (coordinatorLayout != null) {
CollapsingToolbarLayout collapsingToolbarLayout =
findCollapsingToolbarLayoutChildIn(coordinatorLayout);
if (collapsingToolbarLayout != null) {
int toolbarHeight = collapsingToolbarLayout.getHeight();
nestedScrollView.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
nestedScrollView.dispatchNestedPreScroll(0, toolbarHeight, null, null);
}
}
nestedScrollView.scrollTo(0, view.getTop());
} else {
throw new Exception("Unable to find NestedScrollView parent.");
}
} catch (Exception e) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(e)
.build();
}
uiController.loopMainThreadUntilIdle();
}
};
}
private static CollapsingToolbarLayout findCollapsingToolbarLayoutChildIn(ViewGroup viewGroup) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof CollapsingToolbarLayout) {
return (CollapsingToolbarLayout) child;
} else if (child instanceof ViewGroup) {
return findCollapsingToolbarLayoutChildIn((ViewGroup) child);
}
}
return null;
}
private static View findFirstParentLayoutOfClass(View view, Class<? extends View> parentClass) {
ViewParent parent = new FrameLayout(view.getContext());
ViewParent incrementView = null;
int i = 0;
while (parent != null && !(parent.getClass() == parentClass)) {
if (i == 0) {
parent = findParent(view);
} else {
parent = findParent(incrementView);
}
incrementView = parent;
i++;
}
return (View) parent;
}
private static ViewParent findParent(View view) {
return view.getParent();
}
private static ViewParent findParent(ViewParent view) {
return view.getParent();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With