I need to scroll down through my NestedScrollView in order to test my xml file with Espresso, but I get the error message: "Error performing 'scroll to' on view 'with id:"
Several other posts that seem to have a similar problem.
I have followed instructions from this: Android espresso NestedScrollView, how to scroll to bottom
Now I get the forementioned error, and found this post: Scrolling to view was attempted, but the view is not displayed
I have no padding in my NestedScrollView - I even tried removing padding from the XML alltogether, for testing purposes, but it made no difference.
This is my test (so far it is not supposed to do anything, but scroll down):
@Test
public void testScrollDownAbilityOfDetailsScrollView(){
goToSpecificItemOnStream(streamItemWithOneImage);
onView(withId(R.id.end_of_details))
.perform(ScrollToAction.betterScrollTo());
}
It uses a custom made Scroll To Action class:
public final class ScrollToAction implements ViewAction {
private static final String TAG = ScrollToAction.class.getSimpleName();
@SuppressWarnings("unchecked")
@Override
public Matcher<View> getConstraints() {
return allOf(withEffectiveVisibility(Visibility.VISIBLE), isDescendantOfA(anyOf(
isAssignableFrom(ScrollView.class), isAssignableFrom(HorizontalScrollView.class), isAssignableFrom(NestedScrollView.class))));
}
@Override
public void perform(UiController uiController, View view) {
if (isDisplayingAtLeast(80).matches(view)) {
Log.i(TAG, "View is already displayed. Returning.");
return;
}
Rect rect = new Rect();
view.getDrawingRect(rect);
if (!view.requestRectangleOnScreen(rect, true /* immediate */)) {
Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled.");
}
uiController.loopMainThreadUntilIdle();
if (!isDisplayingAtLeast(80).matches(view)) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException(
"Scrolling to view was attempted, but the view is not displayed"))
.build();
}
}
public static ViewAction betterScrollTo() {
return ViewActions.actionWithAssertions(new ScrollToAction());
}
@Override
public String getDescription() {
return "scroll to";
}}
The custom made ScrollToAction class is there because the normal scrollTo method is hardcoded to ScrollView and HorizontalScrollView, but not NestedScrollView.
This is the XML file that I am trying to test:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollView"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/fl"
android:background="#FBFBFB"
android:layout_margin="0dp"
android:layout_width="match_parent"
android:layout_height="350dp">
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<ImageView
android:id="@+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:layout_gravity="left|top"
android:background="@null"
android:src="@drawable/ic_location_white"
android:paddingLeft="-8dp" />
<TextView
android:id="@+id/textViewDistance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/location"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_margin="@dimen/text_margin"
android:layout_gravity="left|top"
android:shadowColor="#262424"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="2"
android:textColor="#FBFBFB"
android:textSize="22dp"
android:singleLine="false"
android:paddingLeft="24dp" />
<TextView
android:id="@+id/textViewPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_margin="@dimen/text_margin"
android:layout_gravity="right|top"
android:shadowColor="#262424"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="2"
android:textColor="#FBFBFB"
android:textSize="22dp"/>
<me.relex.circleindicator.CircleIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:shadowColor="#262424"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="1"/>
</FrameLayout>
<LinearLayout
android:layout_below="@id/fl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/textViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_margin="@dimen/text_margin"
android:textColor="@color/colorCheckTomBlack"
android:textStyle="bold"
android:textSize="20dp" />
<TextView
android:id="@+id/textViewDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/text_margin"
android:layout_marginRight="@dimen/text_margin"
android:gravity="left"
android:textColor="@color/colorCheckTomBlack"
android:textSize="18dp"
android:layout_weight="0.56" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="65dp"
android:paddingTop="30dp">
<ImageButton
android:id="@+id/buttonWatchlist"
android:src="@drawable/ic_checktom"
android:background="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_marginLeft="55dp"
android:layout_marginStart="55dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="launchWatchlistActivity"
android:paddingTop="2dp"/>
<ImageButton
android:id="@+id/buttonMessage"
android:src="@drawable/ic_messages"
android:background="@null"
android:scaleX="1.2"
android:scaleY="1.2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:onClick="launchMessageActivity"
android:paddingTop="7dp"/>
<ImageButton
android:id="@+id/buttonShare"
android:src="@drawable/ic_share"
android:background="@null"
android:scaleX="1.5"
android:scaleY="1.5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="54dp"
android:layout_marginEnd="54dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:onClick="launchShareActivity"/>
</RelativeLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp">
<TextView
android:id="@+id/textViewWatchlist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Watchlist"
android:layout_marginLeft="41dp"
android:layout_marginStart="41dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:id="@+id/textViewMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Message"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
<TextView
android:id="@+id/textViewShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Share"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="52dp"
android:layout_marginEnd="52dp" />
</RelativeLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="_________________________________________"
android:paddingTop="25dp"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView"
android:layout_centerHorizontal="true"
android:id="@+id/circleView"
android:scaleX="0.4"
android:scaleY="0.4"
android:layout_marginTop="-20dp"
android:layout_marginBottom="-60dp"
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:id="@+id/textViewSellerName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18dp"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:id="@+id/textViewSellerDestination"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="20dp" />
<TextView
android:id="@+id/end_of_details"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
When the test fails, this is the full output I get:
android.support.test.espresso.PerformException: Error performing 'scroll to' on view 'with id: com.checktom.checktom:id/end_of_details'. at android.support.test.espresso.PerformException$Builder.build(PerformException.java:83) at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:80) at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:56) at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184) at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115) at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87) at com.checktom.checktom.ApplicationTest.testScrollDownAbilityOfDetailsScrollView(ApplicationTest.java:279) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55) at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:270) at org.junit.rules.RunRules.evaluate(RunRules.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59) at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1933) Caused by: java.lang.RuntimeException: Scrolling to view was attempted, but the view is not displayed at com.checktom.checktom.ScrollToAction.perform(ScrollToAction.java:52) at android.support.test.espresso.ViewInteraction$1.run(ViewInteraction.java:144) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:6938) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199) Tests ran to completion.
I can tell that I run into the runtime exception in my ScrollToAction class's perform method, but I have yet to find a way to solve it.
In the first post I linked, the new BetterScrollTo method seemed to work like a charm.
I did this:
onView(withId(R.id.viewToScroll)
.perform(nestedScrollTo())
.check(matches(isDisplayed()));
Where nestedScrollTo()
is:
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 "View is not NestedScrollView";
}
@Override
public void perform(UiController uiController, View view) {
try {
NestedScrollView nestedScrollView = (NestedScrollView)
findFirstParentLayoutOfClass(view, NestedScrollView.class);
if (nestedScrollView != 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 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();
}