I'm getting the
Got null root node from accessibility - Retrying...
message from the UiAutomator
and I have no idea why.
Shortly:
We're executing the E2E tests on our app and each test starts with the launch activity. The first test runs successfully. When the second test starts, it's all fine until we start finding a UiObject. On that call, we're getting the error.
Detailed:
The first test starts StartActivity
and navigates through the onboarding to the MainScreen
.
Start screen starting:
val intent = Intent(appContext, StartActivity::class.java)
appContext.startActivity(intent)
I've tried like this as well:
val intent = appContext.packageManager.getLaunchIntentForPackage(appContext.originalPackageName).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
appContext.startActivity(intent)
but there is no difference, as test runner checks automatically if there is a running activity after the test run, and clears it.
When the second test is run, it still starts from the StartActivity
but the onboarding process is skipped now, and user (test runner) is navigated to the screen which contains the Continue
button.
Therefore, we're finding an UiObject with the text Continue
and wait for it to appear on the screen. Once it appears, we'll click it. However, as soon as we initiate "finding the Continue button" the message from the title starts appearing and after a couple of seconds everything crashes with:
Test running failed: Instrumentation run failed due to 'Process crashed.'
Snippet:
val continueButton = viewByText { appContext stringOf R.string.all_continue }
continueButton.waitToBecomeVisible(1.minute)
continueButton.click()
I guess the final question would be, what causes the UiAutomator to lose all root nodes?
Debugging the methods in UiDevice
like getUiAutomation
, getWindowRoots
and actual getRootNode()
from QueryContoller
, which is logging the message above, didn't help.
Syntax sugar:
appContext
val appContext: Context get() = InstrumentationRegistry.getTargetContext()
viewByText
:
fun viewByText(text: () -> String): UiObject = device.objectByText { text() }
infix fun UiDevice.objectByText(text: () -> String): UiObject =
findObject(UiSelector().text(text()))
waitToBecomeVisible
:
infix fun UiObject.waitToBecomeVisible(timeOutMillis: Long) {
if(!waitForExists(timeOutMillis)){
throw UiObjectNotFoundException(
"Timeout: ${timeOutMillis.toDouble()/1000}s. ${this.selector}"
)
}
}
I'm feeling obliged to put an answer to this question, as this was not a problem with the UIAutomator
at all.
The message Got null root node from accessibility - Retrying...
is something you'll find in your logs all the time. However, UIAutomator is able to continue after few retries.
In our case, the application we were testing had a SignalR integration with buggy "lifecycle" implementation. In combination with the state described above, when the retry is in progress, SignalR failed with NPE, crashing the app and as a consequence, the test instrumentation process is crashed as well.
It took as a long time to figure out the cause and effects this situation had on the app and the tests, but the good thing, we solved the nasty bug from the SignalR.
Therefore, if it happens that the test instrumentation runner crash with the bunch of Got null...
messages logged, try searching for some other cause, as main thread is blocked during retries and lifecycle aware component might get into the trouble.
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