darek_kce
darek_kce

Reputation: 33

Why the recycler view test is not passed?

I've written the test, testing if the recycler view is displayed (id: comments_view), but it always fails and I've no idea why. When I'm checking for layout (id: cm), the test passes.

I have the following fragment code:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="post"
            type="com.example.kotlinpostapi.apiObjects.Post" />
        <variable
            name="comments"
            type="java.util.List" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".views.MainActivity"
        android:id="@+id/cm">


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/comments_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

The test code (I'm navigating to the fragment from another one):

@RunWith(AndroidJUnit4::class)
class CommentsListTest{

    @get: Rule
    val activityScenario = ActivityScenarioRule(MainActivity::class.java)

    @Test
    fun testCommentsAreDisplayed() {
        onView(withId(R.id.posts_view)).perform(actionOnItemAtPosition<PostAdapter.PostsViewHolder>(0, MyMatchers.clickChildView(R.id.show_comments_button)))

        //it fails
        onView(withId(R.id.comments_view)).check(matches(isDisplayed()))
        //it passes
        onView(withId(R.id.cm)).check(matches(isDisplayed()))
    }
}

How is it possible, and how can I test my recycler view?

Upvotes: 1

Views: 118

Answers (1)

jeprubio
jeprubio

Reputation: 18002

The height of the RecyclerView is set to wrap_content and if the element is not visible at least 90% the test fails.

What you could do is to check one of the RecyclerView children.

I firstly declare the following method:

fun nthChildOf(parentMatcher: Matcher<View?>, childPosition: Int): Matcher<View?>? {
    return object : TypeSafeMatcher<View>() {
        override fun describeTo(description: Description) {
            description.appendText("with $childPosition child view of type parentMatcher")
        }

        override fun matchesSafely(view: View): Boolean {
            if (view.parent !is ViewGroup) {
                return parentMatcher.matches(view.parent)
            }
            val group = view.parent as ViewGroup
            return parentMatcher.matches(view.parent) && group.getChildAt(childPosition) == view
        }
    }
}

with this you can check whether its first child is displayed:

onView(nthChildOf(withId(R.id.comments_view), 0)).check(matches(isDisplayed()))

And to check one element of its children (recyclerview_element_id for example):

onView(allOf(
        withId(R.id.recyclerview_element_id),
        isDescendantOfA(
                nthChildOf(withId(R.id.comments_view), 0))
)).check(matches(isDisplayed()))

Another thing you could try if your RecyclerView expands to the available space of the screen is to change the layout of the RecyclerView to have all the constraints set and with and height to 0dp:

<androidx.recyclerview.widget.RecyclerView
            android:id="@+id/comments_view"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

I have it this way and doing:

onView(withId(R.id.myRecyclerviewId)).check(matches(isDisplayed()))

works for me.

Upvotes: 1

Related Questions