Espresso NestedScrollView

Igo*_*sky 10 android android-testing android-espresso

我试图在我的表单中测试NestedScrollView中的EditTexts.我正在运行以下代码:

onView(withId(R.id.register_scroll_view)).perform(scrollTo()).perform(click());
Run Code Online (Sandbox Code Playgroud)

其中register_scroll_view是我的NestedScrollView.但是,我得到一个例外:

android.support.test.espresso.PerformException:在视图'上执行'滚动到'时出错,ID为:com.eazyigz.myapp:id/register_scroll_view'.引起:java.lang.RuntimeException:不会执行Action,因为目标视图不匹配以下一个或多个约束:(视图具有有效可见性= VISIBLE并且是a的后代:(可从类中分配:class android .widget.ScrollView或可从类中分配:class android.widget.Horizo​​ntalScrollView))

如何正确设计此测试,以便我可以测试需要滚动到可见的EditTexts?

Be_*_*ive 14

我没有任何使用NestedScrollView的经验,但看起来,requestRectangleOnScreen()在常规ScrollView中espresso滚动的方式应该与NestedScrollView一样.

唯一的问题是ScrollView约束被硬编码到scrollTo()动作中,而NestedScrollView不会继承常规的ScrollView.

我相信这里唯一的解决方案是将整个ScrollToAction类复制并粘贴到您自己的此操作实现中,并替换讨厌的约束.

  • 甚至复制 [ScrollToAction](https://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso/core/src/main/java/android/support/test/espresso/action /ScrollToAction.java) 在我也有 NestedScrollView 的情况下不起作用。对我有用的只是简单地使用 `swipeUp()` 而不是 `scrollTo()` (2认同)

F1s*_*her 5

我已经编写了一个 ViewAction 来处理滚动到作为 NestedScrollView 的子视图的视图。它还考虑到 CoordinatorLayout 可能是根 - 所以你不必害怕工具栏改变它的大小。

有一些代码。您需要将此类复制粘贴到您的项目某处。然后你可以像这样使用它:

onView(withId(R.id.register_scroll_view))
        .perform(CustomScrollActions.nestedScrollTo, click());
Run Code Online (Sandbox Code Playgroud)

重要提示:它不是替代scrollTo()它的是另一个滚动 ViewAction,在处理 NestedScrollView 的情况下,您应该使用它。

所以有一个 ViewAction 我正在谈论:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是迄今为止我发现的唯一也适用于动画 BottomNavigationView 的解决方案。 (2认同)