KamilH
10/21/2022, 8:33 AMIdlingResources
in app architecture that uses `Flow`s a lot? In my app I tried to implement similar solution to this however it doesn’t work well, because here we are waiting until job is not active anymore and it’s problematic when we, for example, observe changes in the database, because this kind of streams are not completing at all, which means we inform Espresso that app is busy all the time and tests are not resuming.
Maybe it would be better to inform Espresso that the app is busy only when Flow
is “processing” some value, however that doesn’t seem to be possiblemattinger
10/21/2022, 3:58 PMlaunch
function to increment before launch is called, and decrement when the job completes:
fun CoroutineScope.launchIdling(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
EspressoIdlingResource.increment()
val job = this.launch(context, start, block)
job.invokeOnCompletion { EspressoIdlingResource.decrement() }
return job
}
However, this can be pretty dangerous and error prone because if used in the wrong way, it can just lock up your espresso tests. For instance, collecting from a flow that manages UI state from your view model and updates the ui, would generally be a non terminating flow and would only exit when it’s coroutine scope went away. As such, it would never be considered idle until the composable, fragment or activity that owns it goes completely away.mattinger
10/21/2022, 3:59 PMmattinger
10/21/2022, 4:00 PMclass WaitUntilAction(
private val timeout: Long,
private val description: String,
private val test: (View) -> Boolean
): ViewAction {
override fun getConstraints(): Matcher<View> = Matchers.any(View::class.java)
override fun getDescription(): String = description
override fun perform(uiController: UiController, view: View) {
val startTime = System.currentTimeMillis()
val endTime = startTime + timeout
do {
if (test(view)) {
return
}
uiController.loopMainThreadForAtLeast(50L)
} while (System.currentTimeMillis() < endTime)
throw PerformException.Builder()
.withActionDescription(getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(TimeoutException())
.build()
}
}
KamilH
10/24/2022, 5:47 AMWaitUntilAction
, however I was exploring a way to migrate to something based on CoroutineDispatcher
, but it seems to be not possible easy waymattinger
10/24/2022, 1:21 PM