Skip to content

Robolectric test with clickable item in Compose bottom sheet fails on certain API levels #9595

@bvschaik

Description

@bvschaik

Short description

If you have a Compose bottom sheet with any type of clickable item in it (tested: material 3 Button, regular Image), the onClick handler is not called in Robolectric unit tests on certain API levels: 27 and 29-34.

Description

This is a simple Compose Android app with one button that opens a bottom sheet. In the bottom sheet is a close button to hide the bottom sheet.

Code for the bottom sheet:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyBottomSheet(onDismiss: () -> Unit) {
    val sheetState = rememberModalBottomSheetState()
    val scope = rememberCoroutineScope()
    ModalBottomSheet(
        onDismissRequest = onDismiss,
        sheetState = sheetState
    ) {
        Image(
            imageVector = LocalContext.current.CloseIcon,
            contentDescription = "Close this",
            modifier = Modifier
                .padding(dimensionResource(id = R.dimen.padding))
                .clickable {
                    println("Click was called")
                    scope
                        .launch { sheetState.hide() }
                        .invokeOnCompletion {
                            if (!sheetState.isVisible) {
                                onDismiss()
                            }
                        }
                }
        )
    }
}

The one unit test (not Android test) using Robolectric does the following:

  1. it starts the screen
  2. it clicks the button to open the bottom sheet
  3. it checks that the bottom sheet is visible
  4. it clicks the close button to hide the bottom sheet
  5. it checks that the bottom sheet is now gone

Code for the unit test:

@RunWith(AndroidJUnit4::class)
class ExampleUnitTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun openCloseBottomSheet() {
        with(composeTestRule) {
            setContent {
                MainScreen()
            }
            // Open bottom sheet
            onNode(hasText("Hit me") and hasClickAction())
                .assertIsDisplayed()
                .performClick()

            val closeButton = onNodeWithContentDescription("Close this")

            // Click the close button in the bottom sheet
            closeButton
                .assertIsDisplayed()
                .assertHasClickAction()
                .performClick()

            // Check bottom sheet is indeed gone: this fails on API 27 and 29+
            closeButton.assertIsNotDisplayed()
        }
    }
}

Running this test with Compose BOM 2024.09.01 with Robolectric 4.13:

  • Running on API levels 24-26, 28: the test succeeds (I didn't test < 24)
  • Running on API levels 27, and 29-34: the test fails because the onClick handler of the close button inside the bottom sheet is not called

When downgrading Compose BOM to 2024.04.01, all API levels succeed.

Steps to Reproduce

  1. Clone this repo: https://github.com/bvschaik/compose-robolectric-failure
  2. Open the project using Android Studio and run ExampleUnitTest in that project
  3. Note that the test fails on the last assertion
  4. Now, open app/src/test/resources/robolectric.properties and change the sdk=29 to sdk=28
  5. Note that the test succeeds

Robolectric & Android Version

Robolectric: 4.13
Android version: SDKs 27 and 29-34 are affected. Somehow 28 and <=26 are not.
Compose version: BOM 2024.09.00 and 2024.09.01 are affected (Compose 1.7.0/1.7.1), BOM 2024.04.01 (Compose 1.6.8) is not.

Link to a public git repo demonstrating the problem:

https://github.com/bvschaik/compose-robolectric-failure

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions