我试图在我的表单中测试NestedScrollView中的EditTexts。我正在运行以下代码:
onView(withId(R.id.register_scroll_view)).perform(scrollTo()).perform(click());
其中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.HorizontalScrollView))
如何正确设计此测试,以便我可以测试需要滚动到可见的EditTexts?
我对NestedScrollView没有任何经验,但看起来requestRectangleOnScreen()
,这是常规ScrollView中espresso滚动的方式,应该与NestedScrollView一样工作。
唯一的问题是ScrollView约束被硬编码到scrollTo()
动作中,而NestedScrollView不会继承常规的ScrollView。
我相信这里唯一的解决方案是将整个ScrollToAction类复制并粘贴到您自己的动作实现中,并替换讨厌的约束。
我编写了单个ViewAction来处理滚动到NestedScrollView的子视图。它还考虑到CoordinatorLayout可能是一个根 - 所以你不必害怕工具栏改变它的大小。
有一些代码。您需要将此类复制粘贴到您的项目中。然后你可以使用它,例如:
onView(withId(R.id.register_scroll_view))
.perform(CustomScrollActions.nestedScrollTo, click());
重要提示:它不是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();
}
}
使用
onView(withId(R.id.register_scroll_view))
.perform(swipeUp(), click())