diff --git a/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/idlingresources/OkHttp3IdlingResource.kt b/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/idlingresources/OkHttp3IdlingResource.kt index f0770ff..a0c70d2 100644 --- a/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/idlingresources/OkHttp3IdlingResource.kt +++ b/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/idlingresources/OkHttp3IdlingResource.kt @@ -21,6 +21,7 @@ class OkHttp3IdlingResource private constructor( init { val currentCallback = dispatcher.idleCallback dispatcher.idleCallback = Runnable { + sleepForDispatcherDefaultCallInRetrofitErrorState() callback?.onTransitionToIdle() currentCallback?.run() } @@ -28,7 +29,13 @@ class OkHttp3IdlingResource private constructor( override fun getName(): String = name - override fun isIdleNow(): Boolean = dispatcher.runningCallsCount() == 0 + override fun isIdleNow(): Boolean { + val isIdle = dispatcher.runningCallsCount() == 0 + if (isIdle) { + sleepForDispatcherDefaultCallInRetrofitErrorState() + } + return isIdle + } override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) { this.callback = callback @@ -46,5 +53,20 @@ class OkHttp3IdlingResource private constructor( if (client == null) throw NullPointerException("client == null") return OkHttp3IdlingResource(name, client.dispatcher) } + + /** + * This is required, because in case of Errors Retrofit uses Dispatcher.Default to suspendThrow + * see: retrofit2.KotlinExtensions.kt Exception.suspendAndThrow + * Relevant code issue: https://github.com/square/retrofit/blob/6cd6f7d8287f73909614cb7300fcde05f5719750/retrofit/src/main/java/retrofit2/KotlinExtensions.kt#L121 + * This is the current suggested approach to their problem with Unchecked Exceptions + * + * Sadly Dispatcher.Default cannot be replaced yet, so we can't swap it out in tests: + * https://github.com/Kotlin/kotlinx.coroutines/issues/1365 + * + * This brings us to this sleep for now. + */ + private fun sleepForDispatcherDefaultCallInRetrofitErrorState() { + Thread.sleep(200L) + } } } diff --git a/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/mainThreadSynchronization.kt b/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/mainThreadSynchronization.kt index 25a3518..2c7d4d0 100644 --- a/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/mainThreadSynchronization.kt +++ b/test-util-android/src/main/java/org/fnives/test/showcase/android/testutil/synchronization/mainThreadSynchronization.kt @@ -28,7 +28,7 @@ fun runOnUIAwaitOnCurrent(action: () -> Unit) { fun loopMainThreadFor(delay: Long) { if (Looper.getMainLooper().thread == Thread.currentThread()) { - Thread.sleep(200L) + Thread.sleep(delay) } else { Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainThreadFor(delay)) }