Nurseyit Tursunkulov
Nurseyit Tursunkulov

Reputation: 9380

compose can not test Dialog

I have dialog in compose:

@Composable
fun testgtt() {
    val saveDialogState = remember { mutableStateOf(false) }
    Button(onClick = { saveDialogState.value = true }, modifier = Modifier.testTag(PLACE_TAG)) {
        Text(text = "helllow")
    }

    Dialog(onDismissRequest = { saveDialogState.value = false }) {
        Text(text = "helllow",modifier = Modifier.testTag(BUTTON_TAG))
    }
}

and want to test it:

    @Test
    fun das(){
        composeTestRule.setContent {
            TerTheme {
                testgtt()
            }
        }
        composeTestRule.onRoot(useUnmergedTree = true).printToLog("currentLabelExists")
        composeTestRule.onNodeWithTag(PLACE_TAG).performClick()
        composeTestRule.onNodeWithTag(BUTTON_TAG).assertIsDisplayed()
    }

but I get this error:

java.lang.AssertionError: Failed: assertExists.
Reason: Expected exactly '1' node but found '2' nodes that satisfy: (isRoot)
Nodes found:
1) Node #1 at (l=0.0, t=0.0, r=206.0, b=126.0)px
Has 1 child
2) Node #78 at (l=0.0, t=0.0, r=116.0, b=49.0)px
Has 1 child

Inspite of the fact that I see the Dialog itself.

Upvotes: 11

Views: 8354

Answers (5)

gowtham sunder
gowtham sunder

Reputation: 41

I also faced the same situation where i need to click a button in a dialog in compose. In compose testing cheat sheet they have this matcher call isDialog(), using this you can test the dialog in your UI tests.

Sample test

composeTestRule.onNode(
            isDialog()
                    and
                    hasAnyDescendant(
                        hasText("ok", ignoreCase = true)
                    ),
            useUnmergedTree = true
        ).performClick()

Upvotes: 3

ultra.deep
ultra.deep

Reputation: 1809

Short answer : Use onAllNodesWithText sach as following :

onAllNodesWithText("Your Text")[0].assertIsDisplayed()
onAllNodesWithText("Your Text")[1].assertIsDisplayed()

Details:

According to here this error happens when we have two (or more) text or tag inside the Composable functions...You can check it with this:

onRoot(useUnmergedTree = true).printToLog("TAG")

Upvotes: 4

Haroun Hajem
Haroun Hajem

Reputation: 5628

As @DanielO said you can use the isRoot() selector, see below. That however prints out the same message as before.

A possible workaround is to instead print both root trees using something like composeTestRule.onAllNodes(isRoot()).printToLog("currentLabelExists")

You have to distinctivly select which root you are looking for. By using the selectors:

  • .get( index )
  • .onFirst()
  • .onLast()

When added it should look like this:

  • composeTestRule.onAllNodes(isRoot()).get(1).printToLog("T:")
  • composeTestRule.onAllNodes(isRoot()).onFirst().printToLog("T:")
  • composeTestRule.onAllNodes(isRoot()).onLast().printToLog("T:")

Upvotes: 5

DanielO
DanielO

Reputation: 155

The reason for this error is the line: composeTestRule.onRoot(useUnmergedTree = true).printToLog("currentLabelExists")

onRoot expects a single node, but i suspect both the containing view and the dialog each return their own root (Speculation)

A possible workaround is to instead print both root trees using something like composeTestRule.onAllNodes(isRoot()).printToLog("currentLabelExists")

Upvotes: 5

Nurseyit Tursunkulov
Nurseyit Tursunkulov

Reputation: 9380

use navigation component:

@Composable
fun de(){
    val navController = rememberNavController()
    Scaffold { innerPadding ->
        NavHost(navController, "home", Modifier.padding(innerPadding)) {
            composable("home") {
                // This content fills the area provided to the NavHost
                val saveDialogState = remember { mutableStateOf(true) }
                Button(onClick = {
                                 navController.navigate("detail_dialog")
                }, modifier = Modifier.testTag(PLACE_TAG)) {
                    Text(text = "helllow")
                }
            }
            dialog("detail_dialog") {
                // This content will be automatically added to a Dialog() composable
                // and appear above the HomeScreen or other composable destinations
                
        Dialog(onDismissRequest = {navController.navigate("home")}) {
        Card(
            shape = RoundedCornerShape(10.dp),
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
//                    .padding(horizontal = 16.dp)
                .padding(vertical = 8.dp),
            elevation = 8.dp
        ){
        Text(text = "helllow", modifier = Modifier.testTag(BUTTON_TAG))
        }
    }
            }
        }
    }
}

Upvotes: 0

Related Questions