Skip to main content
Donovan LaDuke - Developer

Complex SemanticMatchers for Compose UI Testing


Featured in Android Weekly Issue 587

When writing UI tests for Compose UI, you will likely find in certain scenarios that the built in matchers are insufficient for identifying the exact node you need to access for testing. Did you know there are methods on SemanticMatcher that allow you to negate or chain the matchers together to better search the semantic tree?

Example #

Let's use this made up UI as we explore the different ways to combine and modify SemanticMatcher elements

Box {
  Column {
    Text("Hello")
    Text("Good-bye")
  }
  Dialog( .. ) {
    Column {
      Text("Hello")
      Text("Good-bye")
    }
  }
}

Intersect with "and" #

You can use the and infix function to select nodes that match both SemanticMatcher elements in the statement. If we wanted to select only the "Hello" text that lives in the Dialog, we could use the following matcher.

hasAnyAncestor(isDialog()) and hasText("Hello")

Union with "or" #

You can use the or infix function to select nodes that match either SemanticMatcher in the statement. If we wanted to select all four Text nodes, we could use the following matcher.

hasText("Hello") or hasText("Good-bye")

Invert with "not" #

You can invert a SemanticMatcher by using the not function or using the ! operator. If we wanted to select all the nodes in the Box, we could use one of the following matchers.

!isRoot()

isRoot().not()

Combining Functions Together #

We can further expand our ability to find the nodes we want by combining multiple functions together! If we wanted to select the "Hello" text that does not live in the Dialog, we could use the following matcher that combines the and and not functions.

hasAnyAncestor(isDialog()).not() and hasText("Hello")

Conclusion #

The ability to modify SemanticMatcher elements greatly expands our ability to express our node selection logic. This in turn allows us to write more comprehensive UI tests, ensuring our apps have better test coverage. If you want to play with this example for yourself, you can check out this gist. Until next time, thanks!

Did you find this content helpful?

Please share this post and be sure to subscribe to the RSS feed to be notified of all future articles!

Want to go above and beyond? Help me out at one of the services below, it goes a long way in helping run this site. Thank you in advance!

Donate with PayPal Buy me a Coffee on Ko-fi Support me on Patreon