In Android Ui testing, I want to click on a spinner item in a dialog, but it pop up with this error:
va.lang.RuntimeException: Waited for the root of the view hierarchy to have window focus and not be requesting layout for over 10 seconds. If you specified a non default root matcher, it may be picking a root that never takes focus. Otherwise, something is seriously wrong. Selected Root:
Root{application-window-token=android.view.ViewRootImpl$W@2dac97c7, window-token=android.view.ViewRootImpl$W@2dac97c7, has-window-focus=false, layout-params-type=1, layout-params-string=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x8 wanim=0x1030461 surfaceInsets=Rect(0, 0 - 0, 0) mwfl=0x0}, decor-view-string=MultiPhoneDecorView{id=-1, visibility=VISIBLE, width=1600, height=2560, has-focus=true, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}
. All Roots:
Root{application-window-token=android.view.ViewRootImpl$W@3c913e1, window-token=android.view.ViewRootImpl$W@21b23506, has-window-focus=true, layout-params-type=1002, layout-params-string=WM.LayoutParams{(310,600)(722x480) gr=#10000033 sim=#1 ty=1002 fl=#1860200 fmt=-3 wanim=0x10302db surfaceInsets=Rect(0, 0 - 0, 0) mwfl=0x0}, decor-view-string=PopupViewContainer{id=-1, visibility=VISIBLE, width=722, height=480, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}
Root{application-window-token=android.view.ViewRootImpl$W@3c913e1, window-token=android.view.ViewRootImpl$W@3c913e1, has-window-focus=false, layout-params-type=2, layout-params-string=WM.LayoutParams{(0,0)(wrapxwrap) gr=#11 sim=#20 ty=2 fl=#1800002 pfl=0x8 fmt=-3 wanim=0x1030462 surfaceInsets=Rect(0, 0 - 0, 0) mwfl=0x10}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1136, height=1058, has-focus=true, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}
Root{application-window-token=android.view.ViewRootImpl$W@2dac97c7, window-token=android.view.ViewRootImpl$W@2dac97c7, has-window-focus=false, layout-params-type=1, layout-params-string=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x8 wanim=0x1030461 surfaceInsets=Rect(0, 0 - 0, 0) mwfl=0x0}, decor-view-string=MultiPhoneDecorView{id=-1, visibility=VISIBLE, width=1600, height=2560, has-focus=true, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}
at android.support.test.espresso.base.RootViewPicker.get(RootViewPicker.java:99)
at android.support.test.espresso.ViewInteractionModule.provideRootView(ViewInteractionModule.java:69)
at android.support.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:23)
at android.support.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:9)
at android.support.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:68)
at android.support.test.espresso.ViewInteraction$1.run(ViewInteraction.java:120)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6117)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
I have tried
onData(allOf(is(instanceOf(String.class)),containsString("A4"))).inRoot(isPlatformPopup()).perform(click());
and
onView(withText(containsString("A4"))).inRoot(isFocusable()).check(matches(isDisplayed()));
and
onView(withText(containsString("A4"))).inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))).check(matches(isDisplayed()));
but none of them works... Can anyone tell me how to get the ralavant root please?
This error can happen when a system dialog is displayed — like "Power Off"
or "Unfortunately, Launcher has stopped"
(a background app crashed) — and you try to run an Espresso unit test whilst that dialog is visible.
Image credit: Android 4.0 emulator always has a crashing Launcher?
You can workaround it in code by dismissing the system dialog before running the test:
// Use the 'testing' Context
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
// Alternative: Use the Activity for the Context
MyActivity activityUnderTest = activityTestRule.getActivity();
activityUnderTest.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
Or send the broadcast on the command line using adb:
adb shell am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS
Another cause of the error is when a background app is frozen (ANR) or is running slowly, and a system dialog appears saying "Launcher isn't responding. Do you want to close it? [Wait] [OK]"
:
Image credit: https://engineering.linkedin.com/blog/2016/08/introducing-and-open-sourcing-test-butler--reliable-android-test
If you try to run an Espresso test while this dialog is visible, the tests will all fail and show the "Waited for the root..." error. There's no easy way to close this dialog programmatically. Espresso cannot click these buttons, for the reasons described here: Dismiss Alert Dialog in Android Espresso Test . However, one way is to use UI Automator to press the "Wait" button in the dialog, just before a test starts:
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
}
companion object {
@JvmStatic
@BeforeClass
fun dismissANRSystemDialog() {
val device = UiDevice.getInstance(getInstrumentation())
// If running the device in English Locale
var waitButton = device.findObject(UiSelector().textContains("wait"))
if (waitButton.exists()) {
waitButton.click()
}
// If running the device in Japanese Locale
waitButton = device.findObject(UiSelector().textContains("待機"))
if (waitButton.exists()) {
waitButton.click()
}
}
}
@BeforeClass
public static void dismissANRSystemDialog() throws UiObjectNotFoundException {
UiDevice device = UiDevice.getInstance(getInstrumentation());
// If the device is running in English Locale
UiObject waitButton = device.findObject(new UiSelector().textContains("wait"));
if (waitButton.exists()) {
waitButton.click();
}
// If the device is running in Japanese Locale
waitButton = device.findObject(new UiSelector().textContains("待機"));
if (waitButton.exists()) {
waitButton.click();
}
}
Alternatively, you could use adb on the command line to send screen taps or key strokes to dismiss it. For example:
# On a 320x480 screen, click at screen location [x=233,y=293] to tap an "OK" dialog button.
# Just in case there is a "Launcher isn't responding" system dialog.
adb shell input tap 233 293
or
# Send keystroke Arrow Right
sleep 3; adb shell input keyevent 22
# Send keystroke Arrow Right again
sleep 3; adb shell input keyevent 22
# Send keystroke Enter to press a button on the dialog
sleep 3; adb shell input keyevent 66
More info:
I had the same error, when I used a Spinner inside a DialogFragment. This is the only code that was working for me:
onView(withText(containsString("A4"))).inRoot(isPlatformPopup()).check(matches(isDisplayed()));
I had similar issue when a dialog popup contains spinner items (dropdown list), my click couldn't perform on any of the spinner items and got the same error. I found a solution by using onData() method with RootMatchers:
onData(anything()).inRoot(RootMatchers.isPlatformPopup()).atPosition(1).perform(click());
Note that, the index value in atPosition() is the item's index value from the spinner list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With