Вы все еще можете реализовать IdlingResource
, не касаясь производственного кода. Вам нужно только создать обратный вызов IdlingResource
, который прослушивает ViewTreeObserver.OnDrawListener
:
private class ViewPropertyChangeCallback(private val matcher: Matcher<View>, private val view: View) : IdlingResource, ViewTreeObserver.OnDrawListener {
private lateinit var callback: IdlingResource.ResourceCallback
private var matched = false
override fun getName() = "View property change callback"
override fun isIdleNow() = matched
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
this.callback = callback
}
override fun onDraw() {
matched = matcher.matches(view)
callback.onTransitionToIdle()
}
}
Затем создайте пользовательский ViewAction
для ожидания совпадения:
fun waitUntil(matcher: Matcher<View>): ViewAction = object : ViewAction {
override fun getConstraints(): Matcher<View> {
return any(View::class.java)
}
override fun getDescription(): String {
return StringDescription().let {
matcher.describeTo(it)
"wait until: $it"
}
}
override fun perform(uiController: UiController, view: View) {
if (!matcher.matches(view)) {
ViewPropertyChangeCallback(matcher, view).run {
try {
IdlingRegistry.getInstance().register(this)
view.viewTreeObserver.addOnDrawListener(this)
uiController.loopMainThreadUntilIdle()
} finally {
view.viewTreeObserver.removeOnDrawListener(this)
IdlingRegistry.getInstance().unregister(this)
}
}
}
}
}
И обновите ваш тест для использования действия:
onView(withId(R.id.hiddenTextView)).perform(waitUntil(isDisplayed()))
// or
onView(withId(R.id.hiddenTextView)).perform(waitUntil(withEffectiveVisibility(VISIBLE)))
.check(matches(isDisplayed()))
Без IdlingResource
, Thread.sleep(...)
может быть вашим следующим вариантом, но он будет нестабильным или неэффективным.