Jetpack Compose UI Test: How to find Node with specific text value if its shown twice

6.4k Views Asked by At

I try to create a ui-test for my android app that is build completly by jetpack compose. I've got e screen where a certain value is shown twice, once as a simple text and second as a label of a button.

How am I able to select the button using that text during my ui-test?

I searched quite a lot and I found something about symantic properties so you could search for a node with a role of type Button but the described matcher function withRole doesn't exist so I'm curious if there's another way I don't see right now.

This was the link I found:

https://proandroiddev.com/test-jetpack-compose-layouts-easily-with-role-semanticproperty-dcf19f64130f

2

There are 2 best solutions below

0
MatPag On BEST ANSWER

In that specific case the extension function withRole is a custom one created by the article writer, this one:

fun withRole(role: Role) = SemanticsMatcher("${SemanticsProperties.Role.name} contains '$role'") {
  val roleProperty = it.config.getOrNull(SemanticsProperties.Role) ?: false
  roleProperty == role
}

you can find the source code here

Another approach could be searching all nodes with that text and then pick the node you need like this?

composeTestRule.onAllNodesWithText("Button")[1]
2
Matt Grier On

If all you need to do is select a button, here is an alternative to by text that can be applied to all components specifically to make testing easier / simpler. You have not posted any code, so the second piece here assumes that you have something like the following:

@get:rule val testRule = createAndroidComposeRule<YourActivity>()

In the view just chain to your modifiers:

modifier = Modifier.whateverElseYouHave().testTag(YOUR_TAG)

In the test:

testRule.onNode(hasTestTag(YOUR_TAG), useUnmergedTree = true).yourAction()

Edit 5/5/23:

This works, in that it selects the button and calls a click action on it:

In the composable:

    Text(text="Test") 
    
    Button(onClick = { 
       Toast.makeText(context, "Test", Toast.LENTH_SHORT).show()
      }) { 
       Text("Test", modifier = Modifier.testTag("TEST_TAG"))
     }

In the test:

testRule.onNode(hasTestTag("TEST_TAG"), useUnmergedTree = true)
.assertIsDisplayed()
.onParent() // Gets the button
.assert(hasClickAction())
.performClick()