From 25e1a8b83ca24c7cbcbe5c5d1955e60a50b85c1b Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 1 Jul 2026 09:27:29 -0500 Subject: [PATCH] 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 --- .../ui/onboarding/OnboardingFlowTest.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/androidTest/kotlin/org/libremail/ui/onboarding/OnboardingFlowTest.kt b/app/src/androidTest/kotlin/org/libremail/ui/onboarding/OnboardingFlowTest.kt index 56dc92b..625a328 100644 --- a/app/src/androidTest/kotlin/org/libremail/ui/onboarding/OnboardingFlowTest.kt +++ b/app/src/androidTest/kotlin/org/libremail/ui/onboarding/OnboardingFlowTest.kt @@ -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))