There are three main ways to interact with UI elements:

- **Finders** let you select one or multiple elements (or *nodes* in the semantics tree) to make assertions or perform actions on them.
- **Assertions** are used to verify that the elements exist or have certain attributes.
- **Actions** inject simulated user events on the elements, such as clicks or other gestures.

Some of these APIs accept a [`SemanticsMatcher`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsMatcher.md.txt) to refer to one or more
*nodes* in the semantics tree.

> [!NOTE]
> **Note:** Testing a Compose UI is different from testing a view-based UI. The view-based UI toolkit clearly defines what a view is. A view occupies a rectangular space and has properties, like identifiers, position, margin, and padding. In Compose, because only some composables *emit* UI into the UI hierarchy, you need a different approach to matching UI elements.

### Finders

You can use [`onNode`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.md.txt#onNode(androidx.compose.ui.test.SemanticsMatcher,kotlin.Boolean)) and [`onAllNodes`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.md.txt#onAllNodes(androidx.compose.ui.test.SemanticsMatcher,kotlin.Boolean)) to select one or multiple nodes
respectively, but you can also use convenience finders for the most common
searches, such as [`onNodeWithText`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/package-summary.md.txt#(androidx.compose.ui.test.SemanticsNodeInteractionsProvider).onNodeWithText(kotlin.String,kotlin.Boolean,kotlin.Boolean,kotlin.Boolean)), and
[`onNodeWithContentDescription`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/package-summary.md.txt#(androidx.compose.ui.test.SemanticsNodeInteractionsProvider).onNodeWithContentDescription(kotlin.String,kotlin.Boolean,kotlin.Boolean,kotlin.Boolean)). You can browse the complete list in the
[Compose Testing cheat sheet](https://developer.android.com/develop/ui/compose/testing-cheatsheet).

#### Select a single node

```kotlin
composeTestRule.onNode(<<SemanticsMatcher>>, useUnmergedTree = false): SemanticsNodeInteraction
```

```kotlin
// Example
composeTestRule
    .onNode(hasText("Button")) // Equivalent to onNodeWithText("Button")
```

#### Select multiple nodes

```kotlin
composeTestRule
    .onAllNodes(<<SemanticsMatcher>>): SemanticsNodeInteractionCollection
```

```kotlin
// Example
composeTestRule
    .onAllNodes(hasText("Button")) // Equivalent to onAllNodesWithText("Button")
```

#### Unmerged tree

Some nodes merge the semantics information of their children. For example, a
button with two text elements merges the text element labels:

```kotlin
MyButton {
    Text("Hello")
    Text("World")
}
```

From a test, use [`printToLog()`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/package-summary.md.txt#(androidx.compose.ui.test.SemanticsNodeInteraction).printToLog(kotlin.String,kotlin.Int)) to show the semantics tree:

```kotlin
composeTestRule.onRoot().printToLog("TAG")
```

This code prints the following output:

    Node #1 at (...)px
     |-Node #2 at (...)px
       Role = 'Button'
       Text = '[Hello, World]'
       Actions = [OnClick, GetTextLayoutResult]
       MergeDescendants = 'true'

If you need to match a node of what would be the *unmerged* tree, you can set
`useUnmergedTree` to `true`:

```kotlin
composeTestRule.onRoot(useUnmergedTree = true).printToLog("TAG")
```

This code prints the following output:

    Node #1 at (...)px
     |-Node #2 at (...)px
       OnClick = '...'
       MergeDescendants = 'true'
        |-Node #3 at (...)px
        | Text = '[Hello]'
        |-Node #5 at (83.0, 86.0, 191.0, 135.0)px
          Text = '[World]'

The `useUnmergedTree` parameter is available in all finders. For example, here
it's used in an `onNodeWithText` finder.

```kotlin
composeTestRule
    .onNodeWithText("World", useUnmergedTree = true).assertIsDisplayed()
```

### Assertions

Check assertions by calling `assert()` on the [`SemanticsNodeInteraction`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.md.txt)
returned by a finder with one or multiple matchers:

```kotlin
// Single matcher:
composeTestRule
    .onNode(matcher)
    .assert(hasText("Button")) // hasText is a SemanticsMatcher

// Multiple matchers can use and / or
composeTestRule
    .onNode(matcher).assert(hasText("Button") or hasText("Button2"))
```

You can also use convenience functions for the most common assertions, such as
[`assertExists`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.md.txt#assertExists(kotlin.String)), [`assertIsDisplayed`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.md.txt#(androidx.compose.ui.test.SemanticsNodeInteraction).assertIsDisplayed()), and [`assertTextEquals`](https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.md.txt#(androidx.compose.ui.test.SemanticsNodeInteraction).assertTextEquals(kotlin.Array,kotlin.Boolean)).
You can browse the complete list in the [Compose Testing cheat sheet](https://developer.android.com/develop/ui/compose/testing-cheatsheet).

There are also functions to check assertions on a collection of nodes:

```kotlin
// Check number of matched nodes
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertCountEquals(4)
// At least one matches
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertAny(hasTestTag("Drummer"))
// All of them match
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertAll(hasClickAction())
```

### Actions

To inject an action on a node, call a `perform...()` function:

```kotlin
composeTestRule.onNode(...).performClick()
```

> [!NOTE]
> **Note:** You cannot chain actions inside a perform function. Instead, make multiple `perform...()` calls.

Here are some examples of actions:

```kotlin
performClick(),
performSemanticsAction(key),
performKeyPress(keyEvent),
performGesture { swipeLeft() }
```

You can browse the complete list in the
[Compose Testing cheat sheet](https://developer.android.com/develop/ui/compose/testing-cheatsheet).

### Matchers

A variety of matchers are available for testing your Compose
code.

#### Hierarchical matchers

Hierarchical matchers let you go up or down the semantics tree and perform
matching.

```kotlin
fun hasParent(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnySibling(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyAncestor(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyDescendant(matcher: SemanticsMatcher):  SemanticsMatcher
```

Here are some examples of these matchers being used:

```kotlin
composeTestRule.onNode(hasParent(hasText("Button")))
    .assertIsDisplayed()
```

#### Selectors

An alternative way to create tests is to use *selectors* which can make some
tests more readable.

```kotlin
composeTestRule.onNode(hasTestTag("Players"))
    .onChildren()
    .filter(hasClickAction())
    .assertCountEquals(4)
    .onFirst()
    .assert(hasText("John"))
```

You can browse the complete list in the [Compose Testing cheat sheet](https://developer.android.com/develop/ui/compose/testing-cheatsheet).

## Additional Resources

- **[Test apps on Android](https://developer.android.com/training/testing.md.txt)**: The main Android testing landing page provides a broader view of testing fundamentals and techniques.
- **[Fundamentals of testing](https://developer.android.com/training/testing/fundamentals.md.txt):** Learn more about the core concepts behind testing an Android app.
- **[Local tests](https://developer.android.com/training/testing/local-tests.md.txt):** You can run some tests locally, on your own workstation.
- **[Instrumented tests](https://developer.android.com/training/testing/instrumented-tests.md.txt):** It is good practice to also run instrumented tests. That is, tests that run directly on-device.
- **[Continuous integration](https://developer.android.com/training/testing/continuous-integration.md.txt):** Continuous integration lets you integrate your tests into your deployment pipeline.
- **[Test different screen sizes](https://developer.android.com/training/testing/different-screens.md.txt):** With some many devices available to users, you should test for different screen sizes.
- **[Espresso](https://developer.android.com/training/testing/espresso.md.txt)**: While intended for View-based UIs, Espresso knowledge can still be helpful for some aspects of Compose testing.