I'm trying to find a way to nicely implement an IdlingResource that will poll a CoroutineDispatcher's isActive property. However, from debugging, there never seems to be an active Job when checking this property.
So far I've tried using AsyncTask's THREAD_POOL_EXECUTOR for built-in idling, but it doesn't seem to work when using the asCoroutineDispatcher extension function and using that resulting CoroutineDispatcher to launch my ViewModel's job. I've attempted writing a custom IdlingResource
ViewModel
fun authenticate(username: String, password: String) = viewModelScope.launch(Dispatchers.Default) {
if (_authenticateRequest.value == true) {
return@launch
}
_authenticateRequest.postValue(true)
val res = loginRepo.authenticate(username, password)
_authenticateRequest.postValue(false)
when {
res is Result.Success -> {
_authenticateSuccess.postValue(res.item)
}
res is Result.Failure && res.statusCode.isHttpClientError -> {
_authenticateFailure.postValue(R.string.invalid_password)
}
else -> {
_authenticateFailure.postValue(R.string.network_error)
}
}
}
IdlingResource
class CoroutineDispatcherIdlingResource(
private val resourceName: String,
private val dispatcher: CoroutineDispatcher
) : IdlingResource {
private var callback: IdlingResource.ResourceCallback? = null
override fun getName() = resourceName
override fun isIdleNow(): Boolean {
if (dispatcher.isActive) { return false }
callback?.onTransitionToIdle()
return true
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
this.callback = callback
}
}
Espresso Test
@RunWith(AndroidJUnit4::class)
class LoginIntegrationTest {
@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)
var idlingResource: CoroutineDispatcherIdlingResource? = null
@Before
fun before() {
idlingResource = CoroutineDispatcherIdlingResource(this.javaClass.simpleName, Dispatchers.Default)
IdlingRegistry.getInstance().register(idlingResource)
}
@Test
fun loginFailure() {
onView(withId(R.id.username))
.perform(clearText()).perform(typeText("aslkdjqwe"))
onView(withId(R.id.password))
.perform(clearText()).perform(typeText("oxicjqwel"))
onView(withId(R.id.login_button))
.perform(click())
onView(withId(com.google.android.material.R.id.snackbar_text))
.check(matches(withText(R.string.invalid_password)))
}
}
I'm expecting the isActive property to be true once the ViewModel 'authenticate' function is called, but this doesn't seem to be the case. It always appears to be false, since there's never an active Job in the CoroutineDispatcher.