android-test
android-test copied to clipboard
Espresso Tests fail on Android 11
Description
I have integration tests running from API 21 to API 29. I've been trying to update our app to target API 30 but the tests are flaky just on API 30.
Steps to Reproduce
- I have a simple case where I tap on a button that should popup a dialog
btnDialog.setOnClickListener {
MaterialAlertDialogBuilder(this).apply {
setTitle("Test Dialog")
setMessage("This should work on API 30")
setPositiveButton(android.R.string.ok, null)
create()
}.show()
}
- Then I try to test it via:
// Given - fragment is launched
launchFragmentInContainer(...)
// When - the button is clicked
onView(withId(R.id.btn_dialog)).perform(click())
// Then - dialog with message should be shown
onView(withText("Test Dialog")).check(matches(isDisplayed()))
onView(withText("This should work on API 30")).check(matches(isDisplayed()))
- I also tried using
RootMatchers.isDialog()
but the same behavior.
Expected Results
This works perfectly from API 21 to API 29. It should also work in API 30. I also turned off all the compatibility changes just to check and it still is happening.
Actual Results
Runtime Exception:
java.lang.RuntimeException: Waited for the root of the view hierarchy to have window focus and not request layout for 10 seconds. If you specified a non default root matcher, it may be picking a root that never takes focus. Root:
Root{application-window-token=android.view.ViewRootImpl$W@e1847f, window-token=android.view.ViewRootImpl$W@e1847f, has-window-focus=false, layout-params-type=1, layout-params-string={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=480, height=854, has-focus=false, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}
at androidx.test.espresso.base.RootViewPicker.waitForRootToBeReady(RootViewPicker.java:69)
at androidx.test.espresso.base.RootViewPicker.pickRootView(RootViewPicker.java:37)
at androidx.test.espresso.base.RootViewPicker.get(RootViewPicker.java:16)
at androidx.test.espresso.ViewInteractionModule.provideRootView(ViewInteractionModule.java:9)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.provideRootView(ViewInteractionModule_ProvideRootViewFactory.java:8)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:6)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:7)
at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:12)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:48)
at androidx.test.espresso.ViewInteraction.access$100(ViewInteraction.java:15)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:3)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:2)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
AndroidX Test and Android OS Versions
AndroidX Test: 1.3.0 Espresso: 3.3.0 Android OS: Android 11 (API 30)
This is still happening on the latest alpha release 1.3.1-alpha03
androidx.test:runner:1.3.1-alpha03
androidx.test:orchestrator:1.3.1-alpha03
androidx.test.espresso:espresso-core:3.4.0-alpha03
seeing the same issue, also launching a dialog on a fragment
it's happing with me also even in Api 29
I'm using 1.4.0-alpha04
for androidx.test and 3.4.0-alpha04
for espresso and it seems to work well with mine now. I have to use inRoot(isDialog())
though so I had to do away with using barista
onView(allOf(withText(text)))
.inRoot(isDialog())
.check(matches(isDisplayed()))
Still happening (Android 11 only!) with androidx.test 1.4.0 / espresso 3.4.0 / target API 30 / compile SDK 31.
Workaround: put a Thread.sleep(2000) to the setup part of the test to provide enough time to restart the app between the test cases.
I was also facing issues with test cases related to Alerts and Dialog windows with Android 30 SDK. The exceptions I observed were java runtime exceptions and were related to no window focus on root view, no matching root found etc. I upgraded androidx.test and espresso to 1.4.0-alpha04 and 3.4.0-alpha04 respectively. And running the tests on Android 11.0 (API 30) devices.
To resolve the issue, I modified test cases to use idling resources in setup method and also included thread.sleep as necessary. I also had to change these settings in the device's developer options: a) Transition animation zoom -> Off b) Window Animation scale -> Off c) Animator duration scale -> Off
This link below provides details on these settings for espresso multi-window support. https://github.com/android/testing-samples/tree/main/ui/espresso/MultiWindowSample
This resolved the runtime exceptions in my case. I hope this helps others too!
It worked for me , inRoot(isDialog())
onView(allOf(withText(text))) .inRoot(isDialog()) .check(matches(isDisplayed()))
Face the same issue asserting text view inside BottomSheetFragment
. I was using Kaspresso/Kako framework and using it.inRoot { isDialog() }
fixed the problem.
val titleTextView = KTextView {
withId(R.id.TitleTextView)
}
}.also { it.inRoot { isDialog() } }
Note: Kako's KAlertDialog
had this in init, for the same reason.
https://github.com/KakaoCup/Kakao/blob/2bfeaa5c4e04fac95096dd0795a753151a99e618/kakao/src/main/kotlin/io/github/kakaocup/kakao/dialog/KAlertDialog.kt#L17-L37
Edit: after this change, the test still fails intermittently.
It works fine for me when I use "it.inRoot { isDialog() } " only on customised alerts, but I still see issue with Android native alerts. Did any one manage to fix it for native alerts?
@kuuuurt We have tests that are running on API 31 that we're seeing almost the exact same stacktrace for and the behavior is not consistent. Many times the tests will run without issues but sometimes those errors will pop up with the same stacktrace. Because we're running on a CI server and the failures are not consistent, I've never actually witnessed the failure occur. I think we are seeing these when trying to test dialogs or dialog fragments.
The thing I'm having trouble understanding is if this error is thrown before our test code is even run. Usually if an Espresso test fails I'll see some indication that some of my test's steps were run from the stacktrace e.g. I'll see an espresso log for a button being clicked and then I'll see some sort of failure but the stacktrace at least includes some Espresso actions that I've coded. In this case I don't see the same thing happening.
When your tests fail with that stacktrace, are you able to determine if your:
onView(withId(R.id.btn_dialog)).perform(click())
is even run?
When your tests fail with that stacktrace, are you able to determine if your: onView(withId(R.id.btn_dialog)).perform(click()) is even run?
What I have observed the button in the dialogue fragment is visible but the test fails to click it.
Ok. I looked deeper into my logcat for the error I'm seeing. In my test, we create a fragment using FragmentScenario, then once it's created, the first thing we attempt to do is call:
Espresso.closeSoftKeyboard()
I noticed in my logs that I get the following output after calling closeSoftKeyboard():
`08-23 23:44:29.917 6274 6328 W .moc: Accessing hidden method Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager; (unsupported, reflection, allowed)
08-23 23:44:29.917 6274 6328 W .moc: Accessing hidden method Landroid/hardware/input/InputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z (unsupported, reflection, allowed)
08-23 23:44:29.917 6274 6328 W .moc: Accessing hidden field Landroid/hardware/input/InputManager;->INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH:I (unsupported, reflection, allowed)
08-23 23:44:29.933 6274 6274 W .moc: Accessing hidden method Landroid/os/MessageQueue;->next()Landroid/os/Message; (unsupported, reflection, allowed)
08-23 23:44:29.933 6274 6274 W .moc: Accessing hidden field Landroid/os/MessageQueue;->mMessages:Landroid/os/Message; (unsupported, reflection, allowed)
08-23 23:44:29.934 6274 6274 W .moc: Accessing hidden method Landroid/os/Message;->recycleUnchecked()V (unsupported, reflection, allowed)
08-23 23:44:29.936 6274 6274 W .moc: Accessing hidden method Landroid/view/WindowManagerGlobal;->getInstance()Landroid/view/WindowManagerGlobal; (unsupported, reflection, allowed)
08-23 23:44:29.937 6274 6274 W .moc: Accessing hidden field Landroid/view/WindowManagerGlobal;->mViews:Ljava/util/ArrayList; (unsupported, reflection, allowed)
08-23 23:44:29.937 6274 6274 W .moc: Accessing hidden field Landroid/view/WindowManagerGlobal;->mParams:Ljava/util/ArrayList; (unsupported, reflection, allowed
08-23 23:44:29.939 6274 6274 D RootViewPicker: Root not ready - waiting: 10ms for one to appear.
08-23 23:44:30.004 6274 6274 D RootViewPicker: Root not ready - waiting: 25ms for one to appear.
08-23 23:44:30.031 1355 1355 I GoogleInputMethodService: GoogleInputMethodService.onFinishInput():3420
08-23 23:44:30.031 1355 1355 I GoogleInputMethodService: GoogleInputMethodService.onStartInput():2002
08-23 23:44:30.032 1355 1355 I DeviceUnlockedTag: DeviceUnlockedTag.notifyDeviceLockStatusChanged():31 Notify device unlocked.
08-23 23:44:30.093 6274 6274 D RootViewPicker: Root not ready - waiting: 50ms for one to appear.
08-23 23:44:30.154 6274 6274 D RootViewPicker: Root not ready - waiting: 100ms for one to appear.
08-23 23:44:30.264 6274 6274 D RootViewPicker: Root not ready - waiting: 200ms for one to appear.
08-23 23:44:30.484 6274 6274 D RootViewPicker: Root not ready - waiting: 400ms for one to appear.
08-23 23:44:30.893 6274 6274 D RootViewPicker: Root not ready - waiting: 800ms for one to appear.
08-23 23:44:31.793 6274 6274 D RootViewPicker: Root not ready - waiting: 1000ms for one to appear.
08-23 23:44:32.845 6274 6274 D RootViewPicker: Root not ready - waiting: 1000ms for one to appear.
08-23 23:44:33.867 6274 6274 D RootViewPicker: Root not ready - waiting: 1000ms for one to appear.
08-23 23:44:34.872 6274 6274 D RootViewPicker: Root not ready - waiting: 1000ms for one to appear. .... Then the failure stack trace `
The Espresso implementation for closeSoftKeyboard() is:
public static void closeSoftKeyboard() { onView(isRoot()).perform(ViewActions.closeSoftKeyboard()); }
So I think the onView(isRoot()) part must be what's causing this issue. I have no idea why it is intermittent though.
i have solved such issue by my own solution in Ultron framework(you can check realisation there). You can find an answer here: https://github.com/open-tool/ultron/wiki/Avoiding-nontrivial-element-lookup-exceptions