Issue#125 Attampt to fix Compose Flakiness

This commit is contained in:
Gergely Hegedus 2022-09-26 21:53:14 +03:00
parent b6b661b055
commit fb411a6b71
2 changed files with 15 additions and 26 deletions

View file

@ -3,15 +3,13 @@ package org.fnives.test.showcase.ui
import androidx.compose.ui.test.MainTestClock import androidx.compose.ui.test.MainTestClock
import androidx.compose.ui.test.junit4.StateRestorationTester import androidx.compose.ui.test.junit4.StateRestorationTester
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.espresso.IdlingRegistry import androidx.test.espresso.Espresso
import androidx.test.espresso.IdlingResource import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import org.fnives.test.showcase.R import org.fnives.test.showcase.R
import org.fnives.test.showcase.android.testutil.intent.DismissSystemDialogsRule import org.fnives.test.showcase.android.testutil.intent.DismissSystemDialogsRule
import org.fnives.test.showcase.android.testutil.screenshot.ScreenshotRule import org.fnives.test.showcase.android.testutil.screenshot.ScreenshotRule
import org.fnives.test.showcase.android.testutil.synchronization.idlingresources.anyResourceNotIdle import org.fnives.test.showcase.android.testutil.viewaction.LoopMainThreadFor
import org.fnives.test.showcase.android.testutil.synchronization.idlingresources.awaitUntilIdle
import org.fnives.test.showcase.android.testutil.synchronization.loopMainThreadFor
import org.fnives.test.showcase.compose.screen.AppNavigation import org.fnives.test.showcase.compose.screen.AppNavigation
import org.fnives.test.showcase.core.integration.fake.FakeUserDataLocalStorage import org.fnives.test.showcase.core.integration.fake.FakeUserDataLocalStorage
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
@ -24,7 +22,6 @@ import org.junit.Test
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.koin.test.KoinTest import org.koin.test.KoinTest
import java.util.concurrent.Executors
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class AuthComposeInstrumentedTest : KoinTest { class AuthComposeInstrumentedTest : KoinTest {
@ -190,25 +187,7 @@ class AuthComposeInstrumentedTest : KoinTest {
* Await the idling resource on a different thread while looping main. * Await the idling resource on a different thread while looping main.
*/ */
fun MainTestClock.awaitIdlingResources() { fun MainTestClock.awaitIdlingResources() {
val idlingRegistry = IdlingRegistry.getInstance() Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadFor(100L))
if (!anyResourceNotIdle()) return
val executor = Executors.newSingleThreadExecutor()
var isIdle = false
executor.submit {
do {
idlingRegistry.resources
.filterNot(IdlingResource::isIdleNow)
.forEach { idlingResource ->
idlingResource.awaitUntilIdle()
}
} while (!idlingRegistry.resources.all(IdlingResource::isIdleNow))
isIdle = true
}
while (!isIdle) {
loopMainThreadFor(200L)
}
executor.shutdown()
advanceTimeByFrame() advanceTimeByFrame()
} }

View file

@ -17,6 +17,7 @@ class OkHttp3IdlingResource private constructor(
) : IdlingResource { ) : IdlingResource {
@Volatile @Volatile
var callback: IdlingResource.ResourceCallback? = null var callback: IdlingResource.ResourceCallback? = null
private var isIdleCallbackWasCalled: Boolean = true
init { init {
val currentCallback = dispatcher.idleCallback val currentCallback = dispatcher.idleCallback
@ -24,12 +25,21 @@ class OkHttp3IdlingResource private constructor(
sleepForDispatcherDefaultCallInRetrofitErrorState() sleepForDispatcherDefaultCallInRetrofitErrorState()
callback?.onTransitionToIdle() callback?.onTransitionToIdle()
currentCallback?.run() currentCallback?.run()
isIdleCallbackWasCalled = true
} }
} }
override fun getName(): String = name override fun getName(): String = name
override fun isIdleNow(): Boolean = dispatcher.runningCallsCount() == 0 override fun isIdleNow(): Boolean {
val isIdle = dispatcher.runningCallsCount() == 0
if (isIdle) {
// sometime the callback is just not properly called it seems, or maybe sync error.
// if it isn't called Espresso crashes, so we add this here.
callback?.onTransitionToIdle()
}
return isIdle
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) { override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
this.callback = callback this.callback = callback