Espresso sometimes does not wait enough for RecyclerView with setHasFixedSize(true) to load
Steps to reproduce:
- Open attached project
- Run ExampleInstrumentedTest couple of times, at least one test will fail eventually
If you add Thread.Sleep to the test or remove setHasFixedSize(true), tests will stop failing RecyclerTest.zip
Migrated from: https://issuetracker.google.com/123653014
@jongerrish Reproduced this with your test project, but I noticed it is using the Support Library
Is this reproducible with AndroidX APIs as well?
(BTW, I enjoyed your Android Dev Summit Testing Rebooted talk a lot 😄 )
(Author of the original ticket here)
Yes, this happens on AndroidX as well. The test project is just most basic reproducible project and Android Studio uses support library by default when creating new project.
Are the APIs identical? If not, then I think probably best to use a test project using AndroidX, no? Maybe I'm missing something here.
Yes, APIs are identical.
I'm seeing this issue as well in an AndroidX project. I ported @matejdro's example source to AndroidX and can reproduce the problem.
Note that this occurs with 1.1.1 (espresso 3.1.1) as well as the current (as of this writing) 1.2.0-beta-01 (espresso 3.2.0-beta01).
For anyone looking for a workaround, I came up with this:
/**
* Stop the test until RecyclerView's data gets loaded.
*
* Passed [recyclerProvider] will be activated in UI thread, allowing you to retrieve the View.
*
* Workaround for https://issuetracker.google.com/issues/123653014
*/
inline fun waitUntilLoaded(crossinline recyclerProvider: () -> RecyclerView) {
Espresso.onIdle()
lateinit var recycler: RecyclerView
InstrumentationRegistry.getInstrumentation().runOnMainSync {
recycler = recyclerProvider()
}
while (recycler.hasPendingAdapterUpdates()) {
Thread.sleep(10)
}
}
Then just call the method before verifying recycler stuff, passng recycler via lambda:
waitUntilLoaded { fragment.recycler }
Is there any progress for this issue?
Another workaround is to set the itemAnimator to null if animation are disabled:
val animatorDurationScale = Settings.Global.getFloat(
context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1F
)
recyclerView.itemAnimator = if (animatorDurationScale == 0F) {
null
} else {
DefaultItemAnimator()
}
Any update on this?
I believe this is still an issue. One option would be to define a RecyclerView idling resource but that requires significant changes to the source code just to support testing, something I'd rather not do.
Are folks using the workarounds in this thread?