Whilst searching online for some suggestions on how to wait for a particular
View
to become visible within an Espresso test, I noticed that all of the suggestions that defined a new ViewAction
class, defined one that operated on the root view. I can see why this is necessary in situations where the View
in question is not present in the view hierarchy and will enter the view hierarchy at a later point. However, if you're waiting on a View
that's present in the view hierarchy to change from one state to another, it's much more elegant to match and operate on that one View
specifically rather than matching and operating on the root view.
So, assuming you're waiting on a
View
that's present in the view hierarchy to change from INVISIBLE
or GONE
visibility to VISIBLE
, you can define a ViewAction
class as follows:
/**
* A [ViewAction] that waits up to [timeout] milliseconds for a [View]'s visibility value to change to [View.VISIBLE].
*/
class WaitUntilVisibleAction(private val timeout: Long) : ViewAction {
override fun getConstraints(): Matcher<View> {
return any(View::class.java)
}
override fun getDescription(): String {
return "wait up to $timeout milliseconds for the view to become visible"
}
override fun perform(uiController: UiController, view: View) {
val endTime = System.currentTimeMillis() + timeout
do {
if (view.visibility == View.VISIBLE) return
uiController.loopMainThreadForAtLeast(50)
} while (System.currentTimeMillis() < endTime)
throw PerformException.Builder()
.withActionDescription(description)
.withCause(TimeoutException("Waited $timeout milliseconds"))
.withViewDescription(HumanReadables.describe(view))
.build()
}
}
And define a function that creates an instance of this
ViewAction
when called, as follows:
/**
* @return a [WaitUntilVisibleAction] instance created with the given [timeout] parameter.
*/
fun waitUntilVisible(timeout: Long): ViewAction {
return WaitUntilVisibleAction(timeout)
}
You can then call on this
ViewAction
in your test methods as follows:
onView(withId(R.id.myView)).perform(waitUntilVisible(3000L))
You can run with this concept and similarly define view actions that wait on other properties of the view to change state, e.g. waiting for the text of a TextView to change to some expected text.
No comments:
Post a Comment