Skip to content

Commit aeb7405

Browse files
@W-21933885: [MSDK Android] App Attestation Implementation (Refactor to use true Espresso IdlingResource synchronization)
Replace manual polling with Espresso.onIdle() for proper IdlingResource handling: - Remove manual while-loop polling and Thread.sleep(50) - Use Espresso.onIdle() to let Espresso handle synchronization - Configure per-wait timeouts using IdlingPolicies.setMasterPolicyTimeout() - Save and restore previous timeout policy to avoid side effects - Improve error messages for timeout exceptions This is the idiomatic Espresso approach where Espresso automatically polls the IdlingResource and waits until isIdleNow() returns true. This provides better integration with Espresso's test infrastructure and more reliable synchronization in Firebase Test Lab.)
1 parent 9ddfa9e commit aeb7405

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/ui/ScreenLockActivityScenarioTest.kt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ import androidx.core.content.ContextCompat.getString
5959
import androidx.core.content.res.ResourcesCompat.getDrawable
6060
import androidx.test.core.app.ActivityScenario.launch
6161
import androidx.test.core.app.ApplicationProvider.getApplicationContext
62+
import androidx.test.espresso.Espresso
63+
import androidx.test.espresso.IdlingPolicies
6264
import androidx.test.espresso.IdlingRegistry
6365
import androidx.test.espresso.IdlingResource
6466
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -120,6 +122,7 @@ class ViewModelIdlingResource(
120122
/**
121123
* Helper function to wait for a condition using IdlingResource.
122124
* Automatically registers and unregisters the idling resource.
125+
* Uses Espresso's built-in synchronization mechanism instead of manual polling.
123126
*
124127
* @param resourceName Name for the idling resource (for debugging)
125128
* @param condition Lambda that returns true when the condition is met
@@ -133,22 +136,32 @@ inline fun <T> waitForCondition(
133136
block: () -> T
134137
): T {
135138
val idlingResource = ViewModelIdlingResource(resourceName, condition)
139+
140+
// Set custom timeout for this wait operation
141+
val previousTimeout = IdlingPolicies.getMasterIdlingPolicy()
142+
IdlingPolicies.setMasterPolicyTimeout(timeoutSeconds, TimeUnit.SECONDS)
143+
136144
IdlingRegistry.getInstance().register(idlingResource)
137145
try {
138-
val startTime = System.currentTimeMillis()
139-
val timeoutMillis = TimeUnit.SECONDS.toMillis(timeoutSeconds)
140-
141-
// Wait for condition with timeout
142-
while (!condition()) {
143-
if (System.currentTimeMillis() - startTime > timeoutMillis) {
144-
throw AssertionError("Timeout waiting for condition '$resourceName' after ${timeoutSeconds}s")
145-
}
146-
Thread.sleep(50) // Poll every 50ms
147-
}
146+
// Let Espresso handle the synchronization - it will poll the IdlingResource
147+
// and wait until isIdleNow() returns true, respecting the timeout policy
148+
Espresso.onIdle()
148149

149150
return block()
151+
} catch (e: Exception) {
152+
// Provide better error message if timeout occurs
153+
if (e.message?.contains("IdlingResource") == true ||
154+
e.message?.contains("timeout") == true) {
155+
throw AssertionError("Timeout waiting for condition '$resourceName' after ${timeoutSeconds}s", e)
156+
}
157+
throw e
150158
} finally {
151159
IdlingRegistry.getInstance().unregister(idlingResource)
160+
// Restore previous timeout policy
161+
IdlingPolicies.setMasterPolicyTimeout(
162+
previousTimeout.idleTimeout,
163+
previousTimeout.idleTimeoutUnit
164+
)
152165
}
153166
}
154167

0 commit comments

Comments
 (0)