-
Notifications
You must be signed in to change notification settings - Fork 0
/
RecyclerViewMatchers.kt
90 lines (76 loc) · 3.27 KB
/
RecyclerViewMatchers.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.tazkiyatech.utils.espresso
import android.view.View
import androidx.annotation.IdRes
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.matcher.BoundedMatcher
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher
/**
* A collection of view matchers for the [RecyclerView] class.
*/
object RecyclerViewMatchers {
/**
* Creates a matcher that matches a [RecyclerView] which contains an adapter with the given number of items.
*
* Usage example:
* ```
* onView(withId(R.id.someRecyclerView)).check(matches(hasAdapterSize(5)))
* ```
*
* @param size The number of items in the adapter of the [RecyclerView] to match on.
* @return A matcher that matches a [RecyclerView] which contains an adapter with the given number of items.
*/
fun hasAdapterSize(size: Int): Matcher<View> {
return HasAdapterSizeMatcher(size)
}
/**
* Creates a matcher that matches the child [View] at the given position
* within the [RecyclerView] which has the given resource id.
*
* Note that it's necessary to scroll the [RecyclerView] to the desired position or close to the desired position
* before attempting to match the child [View] at that position.
* Otherwise, it's likely that the [RecyclerView] will not have rendered the child [View] at that position.
*
* Usage example:
* ```
* onView(withPositionInRecyclerView(R.id.someRecyclerView, 1)).perform(click())
* ```
*
* @param recyclerViewId The resource id of the [RecyclerView] which contains the child [View] to match on.
* @param position The index of the child [View] to match on.
* @return A matcher that matches the child [View] at the given position
* within the [RecyclerView] which has the given resource id.
*/
fun withPositionInRecyclerView(@IdRes recyclerViewId: Int, position: Int): Matcher<View> {
return WithPositionInRecyclerViewMatcher(recyclerViewId, position)
}
private class HasAdapterSizeMatcher(private val size: Int) :
BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description) {
description.appendText("RecyclerView containing adapter with item count $size")
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val adapter = recyclerView.adapter
?: return false // has no adapter
return adapter.itemCount == size
}
}
private class WithPositionInRecyclerViewMatcher(
@IdRes private val recyclerViewId: Int,
private val position: Int
) : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("with position $position in RecyclerView which has id $recyclerViewId")
}
override fun matchesSafely(item: View): Boolean {
val parent = item.parent as? RecyclerView
?: return false
if (parent.id != recyclerViewId)
return false
val viewHolder = parent.findViewHolderForAdapterPosition(position)
?: return false
return item == viewHolder.itemView
}
}
}