[FIXED] UI Test crash using ComposeRule

Issue

I am writing a UI test that goes to a Search screen, conducts a search, and clicks on an item to get to the details of that item. I get a crash on most, but not all of the items the automation test clicks on. I can see that the data loads but crashes while waiting for idle.

Code:

composeTestRule.waitForIdle()

Crash:

Caused by: java.util.concurrent.ExecutionException: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean androidx.compose.ui.node.LayoutNode.getNeedsOnPositionedDispatch$ui_release()' on a null object reference
        at androidx.test.espresso.Espresso.onIdle(Espresso.java:35)
        at androidx.test.espresso.Espresso.onIdle(Espresso.java:21)
        at androidx.compose.ui.test.junit4.EspressoLink_androidKt.runEspressoOnIdle(EspressoLink.android.kt:92)
        at androidx.compose.ui.test.junit4.EspressoLink.runUntilIdle(EspressoLink.android.kt:79)
        at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.waitForIdle(ComposeUiTest.android.kt:308)
        at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$waitForIdle(ComposeUiTest.android.kt:217)
        at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$AndroidComposeUiTestImpl.waitForIdle(ComposeUiTest.android.kt:391)
        at androidx.compose.ui.test.junit4.AndroidComposeTestRule.waitForIdle(AndroidComposeTestRule.android.kt:177)

Update:
I found out that this crashes after "focusRequester.requestFocus()" in my layout, but only if there are items in the list that requests focus. i have checked that focusRequester is not null.

Update 2:
I have uncovered that running "lazyListState.scrollToItem()" when the page loads causes this crash. Seems odd to me but, if i add a delay prior to that call, it works. Still seems like a hack though.

Solution

Fix:
In my case i was using "lazyListState.scrollToItem()" inside the "onFocusChanged" modifier, which requires a coroutine. Taking that code out to a "launchedEffect" fixed this issue

So changing this

.onFocusChanged { event ->
    if (event.isFocused) {
        coroutineScope.launch {
            lazyColumnState.scrollToItem(selectedItemIndex, 0)
        }
    }
}

To this

LaunchedEffect(key1 = hasFocus) {
    if (hasFocus) {
        coroutineScope.launch {
            lazyColumnState.scrollToItem(selectedItemIndex, 0)
        }
    }
}

Answered By – BigApeWhat

Answer Checked By – Senaida (FixeMe Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *