Espresso NestedScrollView

為{幸葍}努か 提交于 2019-12-30 08:15:10

问题


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?


回答1:


I don't have any experience with NestedScrollView, but it appears that requestRectangleOnScreen(), which is how espresso scrolls in the regular ScrollView, should work with NestedScrollView just the same.

The only problem is that ScrollView constrain is hardcoded into the scrollTo() action and NestedScrollView doesn't inherit the regular ScrollView.

I believe the only solution here is to copy and paste entire ScrollToAction class into your own implementation of this action and replace the pesky constrain.




回答2:


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();
    }
}



回答3:


Use

onView(withId(R.id.register_scroll_view))
        .perform(swipeUp(), click())


来源:https://stackoverflow.com/questions/31614937/espresso-nestedscrollview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!