test(onboarding): scroll app-password fields/button into view before tapping

Real cause of the API 29-36 E2E timeout (the earlier 5s->15s bump didn't help,
proving it wasn't slowness): AppPasswordSetupScreen is a scrolling Column and the
"Test and add" button sits below the fold on the short default matrix emulator, so
the positional performClick was a silent no-op -> no add -> no navigation -> the
add-another wait never resolved. It passed on API 37 only because that job uses a
taller pixel_2 AVD. performScrollTo() each field + the button before interacting,
matching the existing pattern in SettingsScreenTest. Verified compileDebugAndroid
TestKotlin + ktlintCheck on JDK 21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 09:27:29 -05:00
co-authored by Claude Opus 4.8
parent 876539b514
commit 25e1a8b83c
@@ -9,6 +9,7 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.compose.ui.test.performTextInput
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavType
@@ -52,10 +53,8 @@ class OnboardingFlowTest {
private fun string(resId: Int) = composeTestRule.activity.getString(resId)
// 15s (not the 5s used elsewhere): the add-another step is reached only after an async chain
// (button → viewModelScope coroutine → addImapAccount → DONE → LaunchedEffect → navigate), which
// on the slower, animation-disabled E2E matrix emulators can exceed a 5s budget for that one
// transition. waitUntil returns as soon as the text appears, so this only raises the cap.
// Generous cap for the slow, animation-disabled CI matrix emulators; waitUntil returns as soon
// as the text appears, so the happy path is unaffected.
private fun waitForText(text: String) = composeTestRule.waitUntil(15_000) {
composeTestRule.onAllNodesWithText(text).fetchSemanticsNodes().isNotEmpty()
}
@@ -194,10 +193,16 @@ class OnboardingFlowTest {
composeTestRule.onNodeWithText("Gmail").performClick()
// App-password setup: email + app password come from the user; servers come from the preset.
// performScrollTo first — on the short default matrix emulator the fields and the "Test and
// add" button sit below the fold of this scrolling screen, and a positional click on an
// off-screen button is a silent no-op (which is why this passed only on API 37's taller AVD).
waitForText(string(R.string.app_password_email))
composeTestRule.onNodeWithText(string(R.string.app_password_email)).performTextInput("e2e@gmail.com")
composeTestRule.onNodeWithText(string(R.string.app_password_field)).performTextInput("app-pass")
composeTestRule.onNodeWithText(string(R.string.app_password_test_and_add)).performClick()
composeTestRule.onNodeWithText(string(R.string.app_password_email))
.performScrollTo().performTextInput("e2e@gmail.com")
composeTestRule.onNodeWithText(string(R.string.app_password_field))
.performScrollTo().performTextInput("app-pass")
composeTestRule.onNodeWithText(string(R.string.app_password_test_and_add))
.performScrollTo().performClick()
// "Add another?" prompt → No.
waitForText(string(R.string.onboarding_add_another_prompt))