'How to test onDismissRequest attribute of AlertDialog?

In its simplest form I have this dialog:


@Composable
fun MyDialog(
    showDialogState: MutableState<Boolean>
) {
    if (showDialogState.value) {
        AlertDialog(onDismissRequest = { showDialogState.value = false },
            // Other irrelevant attributes have been omitted
        )
    }
}

How can I trigger "onDismissRequest" on this composable in Robolectric?

This is usually how I build my composable tests by the way:

@Config(sdk = [Build.VERSION_CODES.O_MR1])
@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
class MyDialogTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun `MyDialog - when showing state and dismissed - changes showing state`() {
        val state = mutableStateOf(true)
        composeTestRule.setContent {
            MyDialog(
                showDialogState = state
            )
        }

        // TODO: How do I trigger dismiss!?
        
        assertFalse(state.value)
    }

}

Compose version: 1.1.0-rc01

Android Gradle Plugin version: 7.0.4

Robolectric version: 4.7.3



Solution 1:[1]

I don't think this is possible at the moment. I have written this test to confirm:

val onButtonPressed = mock<() -> Unit>()

composeTestRule.setContent {
    Scaffold(topBar = {
        TopAppBar {
            Text(text = "This test does not work")
        }
    }) {
        AlertDialog(
            onDismissRequest = {},
            properties = DialogProperties(
                dismissOnBackPress = true,
                dismissOnClickOutside = true
            ),
            title = { Text(text = "This is a dialog")},
            confirmButton = { Button(onClick = {}) {
                Text(text = "Confirm")
            }}
        )
        Column(modifier = Modifier.fillMaxSize()) {
            Spacer(modifier = Modifier.weight(1f))
            Button(onClick = onButtonPressed) {
                Text(text = "test")
            }
        }
    }
}

composeTestRule.onNode(isDialog()).assertExists()

composeTestRule.onNodeWithText("test", ignoreCase = true).performClick()

verify(onButtonPressed).invoke()
        
composeTestRule.onNode(isDialog()).assertDoesNotExist()

Even though the button is "behind" the dialog, it receives click events without dismissing the dialog.

Manual testing has confirmed that the implementation works, so perhaps a UIAutomator test could automate this, but that seems like an overly complicated way of solving this issue.

Solution 2:[2]

I quote the official documentation:

Dismiss the dialog when the user clicks outside the dialog or on the back button. If you want to disable that functionality, simply use an empty onCloseRequest.

https://foso.github.io/Jetpack-Compose-Playground/material/alertdialog/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DanielO
Solution 2 Daniele Ceglia