SemanticsNodeInteraction


Represents a semantics node and the path to fetch it from the semantics tree. One can interact with this node by performing actions such as performClick, assertions such as assertHasClickAction, or navigate to other nodes such as onChildren.

An instance of SemanticsNodeInteraction can be obtained from onNode and convenience methods that use a specific filter, such as onNodeWithText.

Here you can see how you can locate a checkbox, click it and verify that it's checked:

import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.isToggleable
import androidx.compose.ui.test.performClick

composeTestRule.onNode(isToggleable()).performClick().assertIsOn()

useUnmergedTree is for tests with a special need to inspect implementation detail within children. For example:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.dp

composeTestRule.setContent {
    // Box is a semantically merging composable. All testTags of its
    // children are merged up into it in the merged semantics tree.
    Box(Modifier.testTag("box").padding(16.dp)) { Box(Modifier.testTag("icon").size(48.dp)) }
}

// Verify the position of the inner box. Without `useUnmergedTree`, the
// test would check the position of the outer box (which is `(0, 0)`)
// instead of the position of the inner box (which is `(16, 16)`).
composeTestRule
    .onNodeWithTag("icon", useUnmergedTree = true)
    .assertLeftPositionInRootIsEqualTo(16.dp)
    .assertTopPositionInRootIsEqualTo(16.dp)

Summary

Public constructors

SemanticsNodeInteraction(
    testContext: TestContext,
    useUnmergedTree: Boolean,
    matcher: SemanticsMatcher
)
Cmn
SemanticsNodeInteraction(
    testContext: TestContext,
    useUnmergedTree: Boolean,
    selector: SemanticsSelector
)
Cmn

Public functions

Unit

Asserts that no item was found or that the item is no longer in the hierarchy.

Cmn
SemanticsNodeInteraction
assertExists(errorMessageOnFail: String?)

Asserts that the component was found and is part of the component tree.

Cmn
Unit
assertIsDeactivated(errorMessageOnFail: String?)

Asserts that the component was found and it is deactivated.

Cmn
SemanticsNode
fetchSemanticsNode(errorMessageOnFail: String?)

Returns the semantics node captured by this object.

Cmn
Int

Fetch the semantics ID.

Cmn

Extension functions

SemanticsNodeInteraction

Performs a click action on the element represented by the given semantics node.

Cmn
SemanticsNodeInteraction

Finds the CustomAccessibilityAction in the node's CustomActions list whose label is equal to label and then invokes it.

Cmn
SemanticsNodeInteraction
@ExperimentalTestApi
SemanticsNodeInteraction.performCustomAccessibilityActionWithLabelMatching(
    predicateDescription: String?,
    labelPredicate: (label: String) -> Boolean
)

Finds the CustomAccessibilityAction in the node's CustomActions list whose label satisfies a predicate function and then invokes it.

Cmn
SemanticsNodeInteraction

For a first link matching the predicate performs a click on it.

Cmn
SemanticsNodeInteraction

This function is deprecated. Replaced by performTouchInput

Cmn
SemanticsNodeInteraction

Executes the key input gesture specified in the given block.

Cmn
SemanticsNodeInteraction

Executes the mouse gesture specified in the given block.

Cmn
SemanticsNodeInteraction

Executes the multi-modal gesture specified in the given block.

Cmn
SemanticsNodeInteraction

Send the specified RotaryScrollEvent to the focused component.

Cmn
SemanticsNodeInteraction

Scrolls the closest enclosing scroll parent by the smallest amount such that this node is fully visible in its viewport.

Cmn
SemanticsNodeInteraction

Scrolls a scrollable container with items to the item with the given index.

Cmn
SemanticsNodeInteraction

Scrolls a scrollable container with keyed items to the item with the given key, such as LazyColumn or LazyRow.

Cmn
SemanticsNodeInteraction

Scrolls a scrollable container to the content that matches the given matcher.

Cmn
SemanticsNodeInteraction

Provides support to call custom semantics actions on this node.

Cmn
SemanticsNodeInteraction
<T : () -> Boolean> SemanticsNodeInteraction.performSemanticsAction(
    key: SemanticsPropertyKey<AccessibilityAction<T>>,
    invocation: (T) -> Unit
)

Provides support to call custom semantics actions on this node.

Cmn
SemanticsNodeInteraction

Executes the touch gesture specified in the given block.

Cmn
SemanticsNodeInteraction

Requests the focus system to give focus to this node by invoking the RequestFocus semantics action.

Cmn
SemanticsNodeInteraction

Tries to perform accessibility checks on the current screen.

Cmn
android
ImageBitmap

Captures the underlying semantics node's surface into bitmap.

android
SemanticsNodeInteraction
SemanticsNodeInteraction.assert(
    matcher: SemanticsMatcher,
    messagePrefixOnError: (() -> String)?
)

Asserts that the provided matcher is satisfied for this node.

Cmn
SemanticsNodeInteraction
SemanticsNodeInteraction.assertContentDescriptionContains(
    value: String,
    substring: Boolean,
    ignoreCase: Boolean
)

Asserts that the node's content description contains the given value.

Cmn
SemanticsNodeInteraction

Asserts that the node's content description contains exactly the given values and nothing else.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node has a click action.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node has doesn't have a click action.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is displayed on screen.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is enabled.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node has a focus.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is not displayed on screen.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is not enabled.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node does not have a focus.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is not selected.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is unchecked.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is checked.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is selectable.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is selected.

Cmn
SemanticsNodeInteraction

Asserts that the current semantics node is toggleable.

Cmn
SemanticsNodeInteraction

Asserts the node's range info equals the given value.

Cmn
SemanticsNodeInteraction
SemanticsNodeInteraction.assertTextContains(
    value: String,
    substring: Boolean,
    ignoreCase: Boolean
)

Asserts that the node's text contains the given value.

Cmn
SemanticsNodeInteraction
SemanticsNodeInteraction.assertTextEquals(
    vararg values: String,
    includeEditableText: Boolean
)

Asserts that the node's text contains exactly the given values and nothing else.

Cmn
SemanticsNodeInteraction

Asserts the node's value equals the given value.

Cmn
Boolean

Returns true if the matched node is displayed on screen.

Cmn
Boolean

Asserts that the current semantics node is not displayed on screen.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has height that is greater than or equal to expectedMinHeight.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has height equal to expectedHeight.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has the left position in the root composable that is equal to the given position.

Cmn
SemanticsNodeInteraction
SemanticsNodeInteraction.assertPositionInRootIsEqualTo(
    expectedLeft: Dp,
    expectedTop: Dp
)

Asserts that the layout of this node has position in the root composable that is equal to the given position.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has the top position in the root composable that is equal to the given position.

Cmn
SemanticsNodeInteraction

Asserts that the touch bounds of this node has height equal to expectedHeight.

Cmn
SemanticsNodeInteraction

Asserts that the touch bounds of this node has width equal to expectedWidth.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has width that is greater than or equal to expectedMinWidth.

Cmn
SemanticsNodeInteraction

Asserts that the layout of this node has width equal to expectedWidth.

Cmn
Dp

Returns the position of an alignment line, or Dp.Unspecified if the line is not provided.

Cmn
DpRect

Returns the bounds of the layout of this node as clipped to the root.

Cmn
Rect?

Returns the bounds of the first link matching the predicate, or if that link spans multiple lines, returns the bounds of the first line of the link.

Cmn
DpRect

Returns the bounds of the layout of this node.

Cmn
SemanticsNodeInteraction

Executes all of the assertions registered by addGlobalAssertion.

Cmn
Boolean

Send the specified KeyEvent to the focused component.

Cmn
Unit

Prints all the semantics nodes information into logs (as debug level).

Cmn
String

Prints all the semantics nodes information it holds into string.

Cmn
SemanticsNodeInteractionCollection

Returns all the ancestors of this node.

Cmn
SemanticsNodeInteraction

Returns exactly one child of this node.

Cmn
SemanticsNodeInteraction

Returns child of this node at the given index.

Cmn
SemanticsNodeInteractionCollection

Returns children of this node.

Cmn
SemanticsNodeInteraction

Returns a parent of this node.

Cmn
SemanticsNodeInteraction

Returns exactly one sibling of this node.

Cmn
SemanticsNodeInteractionCollection

Returns all siblings of this node.

Cmn
Unit

Sends to this node the IME action associated with it in a similar way to the IME.

Cmn
Unit

Clears the text in this node in similar way to IME.

Cmn
Unit

Sends the given text to this node in similar way to IME.

Cmn
Unit

Sends the given selection to this node in similar way to IME.

Cmn
Unit

Replaces existing text with the given text in this node in similar way to IME.

Cmn

Public constructors

SemanticsNodeInteraction

SemanticsNodeInteraction(
    testContext: TestContext,
    useUnmergedTree: Boolean,
    matcher: SemanticsMatcher
)

SemanticsNodeInteraction

SemanticsNodeInteraction(
    testContext: TestContext,
    useUnmergedTree: Boolean,
    selector: SemanticsSelector
)

Public functions

assertDoesNotExist

fun assertDoesNotExist(): Unit

Asserts that no item was found or that the item is no longer in the hierarchy.

This will synchronize with the UI and fetch all the nodes again to ensure it has latest data.

Throws
kotlin.AssertionError

if the assert fails.

assertExists

fun assertExists(errorMessageOnFail: String? = null): SemanticsNodeInteraction

Asserts that the component was found and is part of the component tree.

This will synchronize with the UI and fetch all the nodes again to ensure it has latest data. If you are using fetchSemanticsNode you don't need to call this. In fact you would just introduce additional overhead.

Parameters
errorMessageOnFail: String? = null

Error message prefix to be added to the message in case this asserts fails. This is typically used by operations that rely on this assert. Example prefix could be: "Failed to perform doOnClick.".

Throws
kotlin.AssertionError

if the assert fails.

assertIsDeactivated

fun assertIsDeactivated(errorMessageOnFail: String? = null): Unit

Asserts that the component was found and it is deactivated.

For example, the children of androidx.compose.ui.layout.SubcomposeLayout which are retained to be reused in future are considered deactivated.

Throws
kotlin.AssertionError

if the assert fails.

fetchSemanticsNode

fun fetchSemanticsNode(errorMessageOnFail: String? = null): SemanticsNode

Returns the semantics node captured by this object.

Note: Accessing this object involves synchronization with your UI. If you are accessing this multiple times in one atomic operation, it is better to cache the result instead of calling this API multiple times.

This will fail if there is 0 or multiple nodes matching.

Throws
kotlin.AssertionError

if 0 or multiple nodes found.

semanticsId

fun semanticsId(): Int

Fetch the semantics ID.

Extension functions

performClick

fun SemanticsNodeInteraction.performClick(): SemanticsNodeInteraction

Performs a click action on the element represented by the given semantics node. Depending on the platform this may be implemented by a touch click (tap), a mouse click, or another more appropriate method for that platform.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performCustomAccessibilityActionWithLabel

@ExperimentalTestApi
fun SemanticsNodeInteraction.performCustomAccessibilityActionWithLabel(
    label: String
): SemanticsNodeInteraction

Finds the CustomAccessibilityAction in the node's CustomActions list whose label is equal to label and then invokes it.

To use your own logic to find the action to perform instead of matching on the full label, use performCustomAccessibilityActionWithLabelMatching.

Parameters
label: String

The exact label of the CustomAccessibilityAction to perform.

Throws
kotlin.AssertionError

If no SemanticsNode is found, or no CustomAccessibilityAction has label, or more than one CustomAccessibilityAction has label.

performCustomAccessibilityActionWithLabelMatching

@ExperimentalTestApi
fun SemanticsNodeInteraction.performCustomAccessibilityActionWithLabelMatching(
    predicateDescription: String? = null,
    labelPredicate: (label: String) -> Boolean
): SemanticsNodeInteraction

Finds the CustomAccessibilityAction in the node's CustomActions list whose label satisfies a predicate function and then invokes it.

Parameters
predicateDescription: String? = null

A description of labelPredicate that will be included in the error message if zero or >1 actions match.

labelPredicate: (label: String) -> Boolean

A predicate function used to select the CustomAccessibilityAction to perform.

performFirstLinkClick

fun SemanticsNodeInteraction.performFirstLinkClick(
    predicate: (AnnotatedString.Range<LinkAnnotation>) -> Boolean = { true }
): SemanticsNodeInteraction

For a first link matching the predicate performs a click on it.

A link in a Text composable is defined by a LinkAnnotation of the AnnotatedString.

import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performFirstLinkClick
import androidx.compose.ui.text.LinkAnnotation

// Example of clicking on a link in test
composeTestRule.onNodeWithText("YOUR_TEXT_WITH_LINK").performFirstLinkClick {
    (it.item as? LinkAnnotation.Url)?.url == "YOUR_URL"
}

performGesture

fun SemanticsNodeInteraction.performGesture(block: GestureScope.() -> Unit): SemanticsNodeInteraction

Executes the (partial) gesture specified in the given block. The gesture doesn't need to be complete and can be resumed in a later invocation of performGesture. The event time is initialized to the current time of the MainTestClock.

Be aware that if you split a gesture over multiple invocations of performGesture, everything that happens in between will run as if the gesture is still ongoing (imagine a finger still touching the screen).

All events that are injected from the block are batched together and sent after block is complete. This method blocks while the events are injected. If an error occurs during execution of block or injection of the events, all (subsequent) events are dropped and the error is thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will take place in between events. Additionally all events will be generated before any of the events take effect. This means that the screen coordinates of all events are resolved before any of the events can cause the position of the node being injected into to change. This has certain advantages, for example, in the cases of nested scrolling or dragging an element around, it prevents the injection of events into a moving target since all events are enqueued before any of them has taken effect.

Example of performing a click:

import androidx.compose.ui.test.click
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performGesture

composeTestRule.onNodeWithTag("myComponent").performGesture { click() }
Parameters
block: GestureScope.() -> Unit

A lambda with GestureScope as receiver that describes the gesture by sending all touch events.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performKeyInput

@ExperimentalTestApi
fun SemanticsNodeInteraction.performKeyInput(block: KeyInjectionScope.() -> Unit): SemanticsNodeInteraction

Executes the key input gesture specified in the given block. The gesture doesn't need to be complete and can be resumed in a later invocation of one of the perform.*Input methods. The event time is initialized to the current time of the MainTestClock.

All events that are injected from the block are batched together and sent after block is complete. This method blocks while the events are injected. If an error occurs during execution of block or injection of the events, all (subsequent) events are dropped and the error is thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will take place in between events. Additionally all events will be generated before any of the events take effect. This means that the screen coordinates of all events are resolved before any of the events can cause the position of the node being injected into to change. This has certain advantages, for example, in the cases of nested scrolling or dragging an element around, it prevents the injection of events into a moving target since all events are enqueued before any of them has taken effect.

Parameters
block: KeyInjectionScope.() -> Unit

A lambda with KeyInjectionScope as receiver that describes the gesture by sending all key press events.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performMouseInput

fun SemanticsNodeInteraction.performMouseInput(block: MouseInjectionScope.() -> Unit): SemanticsNodeInteraction

Executes the mouse gesture specified in the given block. The gesture doesn't need to be complete and can be resumed in a later invocation of one of the perform.*Input methods. The event time is initialized to the current time of the MainTestClock.

Be aware that if you split a gesture over multiple invocations of perform.*Input, everything that happens in between will run as if the gesture is still ongoing (imagine a mouse button still being pressed).

All events that are injected from the block are batched together and sent after block is complete. This method blocks while the events are injected. If an error occurs during execution of block or injection of the events, all (subsequent) events are dropped and the error is thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will take place in between events. Additionally all events will be generated before any of the events take effect. This means that the screen coordinates of all events are resolved before any of the events can cause the position of the node being injected into to change. This has certain advantages, for example, in the cases of nested scrolling or dragging an element around, it prevents the injection of events into a moving target since all events are enqueued before any of them has taken effect.

Example of performing a mouse click:

import androidx.compose.ui.test.click
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performMouseInput

composeTestRule.onNodeWithTag("myComponent").performMouseInput {
    // Click in the middle of the node
    click(center)
}

Example of scrolling the mouse wheel while the mouse button is pressed:

import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performMouseInput

composeTestRule
    .onNodeWithTag("verticalScrollable")
    // Scroll downwards while keeping a button pressed:
    .performMouseInput {
        // Presses the primary mouse button
        press()
        // Scroll the scroll wheel by 6 units
        repeat(6) {
            advanceEventTime()
            scroll(1f)
        }
        // And release the mouse button
        advanceEventTime()
        release()
    }
Parameters
block: MouseInjectionScope.() -> Unit

A lambda with MouseInjectionScope as receiver that describes the gesture by sending all mouse events.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performMultiModalInput

fun SemanticsNodeInteraction.performMultiModalInput(block: MultiModalInjectionScope.() -> Unit): SemanticsNodeInteraction

Executes the multi-modal gesture specified in the given block. The gesture doesn't need to be complete and can be resumed in a later invocation of one of the perform.*Input methods. The event time is initialized to the current time of the MainTestClock. If only a single modality is needed (e.g. touch, mouse, stylus, keyboard, etc), you should use the perform.*Input of that modality instead.

Functions for each modality can be called by invoking that modality's function, like touch to inject touch events. This allows you to inject events for each modality.

Be aware that if you split a gesture over multiple invocations of perform.*Input, everything that happens in between will run as if the gesture is still ongoing (imagine a finger still touching the screen).

All events that are injected from the block are batched together and sent after block is complete. This method blocks while the events are injected. If an error occurs during execution of block or injection of the events, all (subsequent) events are dropped and the error is thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will take place in between events. Additionally all events will be generated before any of the events take effect. This means that the screen coordinates of all events are resolved before any of the events can cause the position of the node being injected into to change. This has certain advantages, for example, in the cases of nested scrolling or dragging an element around, it prevents the injection of events into a moving target since all events are enqueued before any of them has taken effect.

Parameters
block: MultiModalInjectionScope.() -> Unit

A lambda with MultiModalInjectionScope as receiver that describes the gesture by sending all multi modal events.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performRotaryScrollInput

@ExperimentalTestApi
fun SemanticsNodeInteraction.performRotaryScrollInput(block: RotaryInjectionScope.() -> Unit): SemanticsNodeInteraction

Send the specified RotaryScrollEvent to the focused component.

Returns
SemanticsNodeInteraction

true if the event was consumed. False otherwise.

performScrollTo

fun SemanticsNodeInteraction.performScrollTo(): SemanticsNodeInteraction

Scrolls the closest enclosing scroll parent by the smallest amount such that this node is fully visible in its viewport. If this node is larger than the viewport, scrolls the scroll parent by the smallest amount such that this node fills the entire viewport. A scroll parent is a parent node that has the semantics action SemanticsActions.ScrollBy (usually implemented by defining scrollBy).

This action should be performed on the node that is part of the scrollable content, not on the scrollable container.

Throws an AssertionError if there is no scroll parent.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performScrollToIndex

fun SemanticsNodeInteraction.performScrollToIndex(index: Int): SemanticsNodeInteraction

Scrolls a scrollable container with items to the item with the given index.

Note that not all scrollable containers have item indices. For example, a scrollable doesn't have items with an index, while LazyColumn does.

This action should be performed on a node that is a scrollable container, not on a node that is part of the content of that container.

Throws an AssertionError if the node doesn't have ScrollToIndex defined.

Parameters
index: Int

The index of the item to scroll to

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performScrollToKey

fun SemanticsNodeInteraction.performScrollToKey(key: Any): SemanticsNodeInteraction

Scrolls a scrollable container with keyed items to the item with the given key, such as LazyColumn or LazyRow.

This action should be performed on a node that is a scrollable container, not on a node that is part of the content of that container.

Throws an AssertionError if the node doesn't have IndexForKey or ScrollToIndex defined.

Parameters
key: Any

The key of the item to scroll to

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

performScrollToNode

fun SemanticsNodeInteraction.performScrollToNode(
    matcher: SemanticsMatcher
): SemanticsNodeInteraction

Scrolls a scrollable container to the content that matches the given matcher. If the content isn't yet visible, the scrollable container will be scrolled from the start till the end till it finds the content we're looking for. It is not defined where in the viewport the content will be on success of this function, but it will be either fully within the viewport if it is smaller than the viewport, or it will cover the whole viewport if it is larger than the viewport. If it doesn't find the content, the scrollable will be left at the end of the content and an AssertionError is thrown.

This action should be performed on a node that is a scrollable container, not on a node that is part of the content of that container. If the container is a lazy container, it must support the semantics actions ScrollToIndex, ScrollBy, and either HorizontalScrollAxisRange or VerticalScrollAxisRange, for example LazyColumn and LazyRow. If the container is not lazy, it must support the semantics action ScrollBy, for example, Row or Column.

Throws an AssertionError if the scrollable node doesn't support the necessary semantics actions.

Parameters
matcher: SemanticsMatcher

A matcher that identifies the content where the scrollable container needs to scroll to

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method. Note that this is not an interaction for the node that is identified by the matcher.

performSemanticsAction

fun SemanticsNodeInteraction.performSemanticsAction(
    key: SemanticsPropertyKey<AccessibilityAction<() -> Boolean>>
): SemanticsNodeInteraction

Provides support to call custom semantics actions on this node.

This method is for calling actions that have no parameters.

This will properly verify that the actions exists and provide clear error message in case it does not. It also handle synchronization and performing the action on the UI thread. This call is blocking until the action is performed

Parameters
key: SemanticsPropertyKey<AccessibilityAction<() -> Boolean>>

Key of the action to be performed.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

Throws
kotlin.AssertionError

If the semantics action is not defined on this node.

performSemanticsAction

fun <T : () -> Boolean> SemanticsNodeInteraction.performSemanticsAction(
    key: SemanticsPropertyKey<AccessibilityAction<T>>,
    invocation: (T) -> Unit
): SemanticsNodeInteraction

Provides support to call custom semantics actions on this node.

This method is supposed to be used for actions with parameters.

This will properly verify that the actions exists and provide clear error message in case it does not. It also handle synchronization and performing the action on the UI thread. This call is blocking until the action is performed

Parameters
key: SemanticsPropertyKey<AccessibilityAction<T>>

Key of the action to be performed.

invocation: (T) -> Unit

Place where you call your action. In the argument is provided the underlying action from the given Semantics action.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

Throws
kotlin.AssertionError

If the semantics action is not defined on this node.

performTouchInput

fun SemanticsNodeInteraction.performTouchInput(block: TouchInjectionScope.() -> Unit): SemanticsNodeInteraction

Executes the touch gesture specified in the given block. The gesture doesn't need to be complete and can be resumed in a later invocation of one of the perform.*Input methods. The event time is initialized to the current time of the MainTestClock.

Be aware that if you split a gesture over multiple invocations of perform.*Input, everything that happens in between will run as if the gesture is still ongoing (imagine a finger still touching the screen).

All events that are injected from the block are batched together and sent after block is complete. This method blocks while the events are injected. If an error occurs during execution of block or injection of the events, all (subsequent) events are dropped and the error is thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will take place in between events. Additionally all events will be generated before any of the events take effect. This means that the screen coordinates of all events are resolved before any of the events can cause the position of the node being injected into to change. This has certain advantages, for example, in the cases of nested scrolling or dragging an element around, it prevents the injection of events into a moving target since all events are enqueued before any of them has taken effect.

Example of performing a swipe up:

import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeUp

composeTestRule.onNodeWithTag("myComponent").performTouchInput { swipeUp() }

Example of performing an off-center click:

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.test.click
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput

composeTestRule.onNodeWithTag("myComponent").performTouchInput {
    click(percentOffset(.2f, .5f))
}

Example of doing an assertion during a click:

import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput

composeTestRule
    .onNodeWithTag("myComponent")
    .performTouchInput { down(topLeft) }
    .assertHasClickAction()
    .performTouchInput { up() }

Example of performing a click-and-drag:

import androidx.compose.ui.test.click
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeUp

composeTestRule.onNodeWithTag("myComponent").performTouchInput {
    click()
    advanceEventTime(100)
    swipeUp()
}
Parameters
block: TouchInjectionScope.() -> Unit

A lambda with TouchInjectionScope as receiver that describes the gesture by sending all touch events.

Returns
SemanticsNodeInteraction

The SemanticsNodeInteraction that is the receiver of this method

requestFocus

fun SemanticsNodeInteraction.requestFocus(): SemanticsNodeInteraction

Requests the focus system to give focus to this node by invoking the RequestFocus semantics action.

tryPerformAccessibilityChecks

fun SemanticsNodeInteraction.tryPerformAccessibilityChecks(): SemanticsNodeInteraction

Tries to perform accessibility checks on the current screen. This will only actually do something if (1) accessibility checks are enabled and (2) accessibility checks are implemented for the platform on which the test runs.

Throws
kotlin.AssertionError

if accessibility problems are found

captureToImage

@RequiresApi(value = 26)
fun SemanticsNodeInteraction.captureToImage(): ImageBitmap

Captures the underlying semantics node's surface into bitmap. This can be used to capture nodes in a normal composable, a dialog if API >=28 and in a Popup. Note that the mechanism used to capture the bitmap from a Popup is not the same as from a normal composable, since a PopUp is in a different window.

Throws
kotlin.IllegalArgumentException

if we attempt to capture a bitmap of a dialog before API 28.

fun SemanticsNodeInteraction.assert(
    matcher: SemanticsMatcher,
    messagePrefixOnError: (() -> String)? = null
): SemanticsNodeInteraction

Asserts that the provided matcher is satisfied for this node.

Parameters
matcher: SemanticsMatcher

Matcher to verify.

messagePrefixOnError: (() -> String)? = null

Prefix to be put in front of an error that gets thrown in case this assert fails. This can be helpful in situations where this assert fails as part of a bigger operation that used this assert as a precondition check.

Throws
kotlin.AssertionError

if the matcher does not match or the node can no longer be found.

assertContentDescriptionContains

fun SemanticsNodeInteraction.assertContentDescriptionContains(
    value: String,
    substring: Boolean = false,
    ignoreCase: Boolean = false
): SemanticsNodeInteraction

Asserts that the node's content description contains the given value.

Note that in merged semantics tree there can be a list of content descriptions that got merged from the child nodes. Typically an accessibility tooling will decide based on its heuristics which ones to announce.

Throws AssertionError if the node's value does not contain value, or if the node has no value

Parameters
value: String

Value to match as one of the items in the list of content descriptions.

substring: Boolean = false

Whether this can be satisfied as a substring match of an item in the list of descriptions.

ignoreCase: Boolean = false

Whether case should be ignored.

assertContentDescriptionEquals

fun SemanticsNodeInteraction.assertContentDescriptionEquals(
    vararg values: String
): SemanticsNodeInteraction

Asserts that the node's content description contains exactly the given values and nothing else.

Note that in merged semantics tree there can be a list of content descriptions that got merged from the child nodes. Typically an accessibility tooling will decide based on its heuristics which ones to announce.

Throws AssertionError if the node's descriptions don't contain all items from values, or if the descriptions contain extra items that are not in values.

Parameters
vararg values: String

List of values to match (the order does not matter)

assertHasClickAction

fun SemanticsNodeInteraction.assertHasClickAction(): SemanticsNodeInteraction

Asserts that the current semantics node has a click action.

Throws AssertionError if the node is doesn't have a click action.

assertHasNoClickAction

fun SemanticsNodeInteraction.assertHasNoClickAction(): SemanticsNodeInteraction

Asserts that the current semantics node has doesn't have a click action.

Throws AssertionError if the node has a click action.

assertIsDisplayed

fun SemanticsNodeInteraction.assertIsDisplayed(): SemanticsNodeInteraction

Asserts that the current semantics node is displayed on screen.

Specifically, the node must be composed, placed and at least a portion of its bounds must be visible on screen after clipping is applied.

Throws AssertionError if the node is not displayed.

assertIsEnabled

fun SemanticsNodeInteraction.assertIsEnabled(): SemanticsNodeInteraction

Asserts that the current semantics node is enabled.

Throws AssertionError if the node is not enabled or does not define the property at all.

assertIsFocused

fun SemanticsNodeInteraction.assertIsFocused(): SemanticsNodeInteraction

Asserts that the current semantics node has a focus.

Throws AssertionError if the node is not in the focus or does not defined the property at all.

assertIsNotDisplayed

fun SemanticsNodeInteraction.assertIsNotDisplayed(): SemanticsNodeInteraction

Asserts that the current semantics node is not displayed on screen.

Throws AssertionError if the node is displayed.

assertIsNotEnabled

fun SemanticsNodeInteraction.assertIsNotEnabled(): SemanticsNodeInteraction

Asserts that the current semantics node is not enabled.

Throws AssertionError if the node is enabled or does not defined the property at all.

assertIsNotFocused

fun SemanticsNodeInteraction.assertIsNotFocused(): SemanticsNodeInteraction

Asserts that the current semantics node does not have a focus.

Throws AssertionError if the node is in the focus or does not defined the property at all.

assertIsNotSelected

fun SemanticsNodeInteraction.assertIsNotSelected(): SemanticsNodeInteraction

Asserts that the current semantics node is not selected.

Throws AssertionError if the node is selected or not selectable.

assertIsOff

fun SemanticsNodeInteraction.assertIsOff(): SemanticsNodeInteraction

Asserts that the current semantics node is unchecked.

Throws AssertionError if the node is checked, indeterminate, or not toggleable.

assertIsOn

fun SemanticsNodeInteraction.assertIsOn(): SemanticsNodeInteraction

Asserts that the current semantics node is checked.

Throws AssertionError if the node is not unchecked, indeterminate, or not toggleable.

assertIsSelectable

fun SemanticsNodeInteraction.assertIsSelectable(): SemanticsNodeInteraction

Asserts that the current semantics node is selectable.

Throws AssertionError if the node is not selectable.

assertIsSelected

fun SemanticsNodeInteraction.assertIsSelected(): SemanticsNodeInteraction

Asserts that the current semantics node is selected.

Throws AssertionError if the node is unselected or not selectable.

assertIsToggleable

fun SemanticsNodeInteraction.assertIsToggleable(): SemanticsNodeInteraction

Asserts that the current semantics node is toggleable.

Throws AssertionError if the node is not toggleable.

assertRangeInfoEquals

fun SemanticsNodeInteraction.assertRangeInfoEquals(
    value: ProgressBarRangeInfo
): SemanticsNodeInteraction

Asserts the node's range info equals the given value.

For further details please check SemanticsProperties.ProgressBarRangeInfo. Throws AssertionError if the node's value is not equal to value, or if the node has no value

assertTextContains

fun SemanticsNodeInteraction.assertTextContains(
    value: String,
    substring: Boolean = false,
    ignoreCase: Boolean = false
): SemanticsNodeInteraction

Asserts that the node's text contains the given value.

This will also search in SemanticsProperties.EditableText.

Note that in merged semantics tree there can be a list of text items that got merged from the child nodes. Typically an accessibility tooling will decide based on its heuristics which ones to use.

Throws AssertionError if the node's value does not contain value, or if the node has no value

Parameters
value: String

Value to match as one of the items in the list of text values.

substring: Boolean = false

Whether this can be satisfied as a substring match of an item in the list of text.

ignoreCase: Boolean = false

Whether case should be ignored.

See also
Text

assertTextEquals

fun SemanticsNodeInteraction.assertTextEquals(
    vararg values: String,
    includeEditableText: Boolean = true
): SemanticsNodeInteraction

Asserts that the node's text contains exactly the given values and nothing else.

This will also search in SemanticsProperties.EditableText by default.

Note that in merged semantics tree there can be a list of text items that got merged from the child nodes. Typically an accessibility tooling will decide based on its heuristics which ones to use.

Throws AssertionError if the node's text values don't contain all items from values, or if the text values contain extra items that are not in values.

Parameters
vararg values: String

List of values to match (the order does not matter)

includeEditableText: Boolean = true

Whether to also assert against the editable text.

assertValueEquals

fun SemanticsNodeInteraction.assertValueEquals(value: String): SemanticsNodeInteraction

Asserts the node's value equals the given value.

For further details please check SemanticsProperties.StateDescription. Throws AssertionError if the node's value is not equal to value, or if the node has no value

isDisplayed

fun SemanticsNodeInteraction.isDisplayed(): Boolean

Returns true if the matched node is displayed on screen.

Specifically, the node must be composed, placed and at least a portion of its bounds must be visible on screen after clipping is applied. If no matching node is found, returns false. If multiple nodes match, throws an AssertionError.

import androidx.compose.ui.test.isDisplayed
import androidx.compose.ui.test.onNodeWithTag

val interaction = composeTestRule.onNodeWithTag("test")
composeTestRule.waitUntil { interaction.isDisplayed() }
Throws
kotlin.AssertionError

If multiple nodes match this SemanticsNodeInteraction.

isNotDisplayed

fun SemanticsNodeInteraction.isNotDisplayed(): Boolean

Asserts that the current semantics node is not displayed on screen.

If no matching node is found, returns true. If multiple nodes match, throws an AssertionError.

import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.onNodeWithTag

val interaction = composeTestRule.onNodeWithTag("test")
composeTestRule.waitUntil { interaction.isNotDisplayed() }
Throws
kotlin.AssertionError

If multiple nodes match this SemanticsNodeInteraction.

assertHeightIsAtLeast

fun SemanticsNodeInteraction.assertHeightIsAtLeast(expectedMinHeight: Dp): SemanticsNodeInteraction

Asserts that the layout of this node has height that is greater than or equal to expectedMinHeight.

Throws
kotlin.AssertionError

if comparison fails.

assertHeightIsEqualTo

fun SemanticsNodeInteraction.assertHeightIsEqualTo(expectedHeight: Dp): SemanticsNodeInteraction

Asserts that the layout of this node has height equal to expectedHeight.

Throws
kotlin.AssertionError

if comparison fails.

assertLeftPositionInRootIsEqualTo

fun SemanticsNodeInteraction.assertLeftPositionInRootIsEqualTo(
    expectedLeft: Dp
): SemanticsNodeInteraction

Asserts that the layout of this node has the left position in the root composable that is equal to the given position.

Parameters
expectedLeft: Dp

The left (x) position to assert.

Throws
kotlin.AssertionError

if comparison fails.

assertPositionInRootIsEqualTo

fun SemanticsNodeInteraction.assertPositionInRootIsEqualTo(
    expectedLeft: Dp,
    expectedTop: Dp
): SemanticsNodeInteraction

Asserts that the layout of this node has position in the root composable that is equal to the given position.

Parameters
expectedLeft: Dp

The left (x) position to assert.

expectedTop: Dp

The top (y) position to assert.

Throws
kotlin.AssertionError

if comparison fails.

assertTopPositionInRootIsEqualTo

fun SemanticsNodeInteraction.assertTopPositionInRootIsEqualTo(
    expectedTop: Dp
): SemanticsNodeInteraction

Asserts that the layout of this node has the top position in the root composable that is equal to the given position.

Parameters
expectedTop: Dp

The top (y) position to assert.

Throws
kotlin.AssertionError

if comparison fails.

assertTouchHeightIsEqualTo

fun SemanticsNodeInteraction.assertTouchHeightIsEqualTo(
    expectedHeight: Dp
): SemanticsNodeInteraction

Asserts that the touch bounds of this node has height equal to expectedHeight.

Throws
kotlin.AssertionError

if comparison fails.

assertTouchWidthIsEqualTo

fun SemanticsNodeInteraction.assertTouchWidthIsEqualTo(expectedWidth: Dp): SemanticsNodeInteraction

Asserts that the touch bounds of this node has width equal to expectedWidth.

Throws
kotlin.AssertionError

if comparison fails.

assertWidthIsAtLeast

fun SemanticsNodeInteraction.assertWidthIsAtLeast(expectedMinWidth: Dp): SemanticsNodeInteraction

Asserts that the layout of this node has width that is greater than or equal to expectedMinWidth.

Throws
kotlin.AssertionError

if comparison fails.

assertWidthIsEqualTo

fun SemanticsNodeInteraction.assertWidthIsEqualTo(expectedWidth: Dp): SemanticsNodeInteraction

Asserts that the layout of this node has width equal to expectedWidth.

Throws
kotlin.AssertionError

if comparison fails.

getAlignmentLinePosition

fun SemanticsNodeInteraction.getAlignmentLinePosition(
    alignmentLine: AlignmentLine
): Dp

Returns the position of an alignment line, or Dp.Unspecified if the line is not provided.

getBoundsInRoot

fun SemanticsNodeInteraction.getBoundsInRoot(): DpRect

Returns the bounds of the layout of this node as clipped to the root. The bounds are relative to the root composable.

getFirstLinkBounds

fun SemanticsNodeInteraction.getFirstLinkBounds(
    predicate: (AnnotatedString.Range<LinkAnnotation>) -> Boolean = { true }
): Rect?

Returns the bounds of the first link matching the predicate, or if that link spans multiple lines, returns the bounds of the first line of the link.

A link in a Text composable is defined by a LinkAnnotation of the AnnotatedString.

The bounds are in the text node's coordinate system.

You can pass an offset from within the bounds to injection methods to operate them on the link, for example TouchInjectionScope.click or MouseInjectionScope.moveTo.

import androidx.compose.ui.test.getFirstLinkBounds
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performMouseInput
import androidx.compose.ui.text.LinkAnnotation

// Example of hovering over the first link in test
val firstLinkBounds =
    composeTestRule.onNodeWithText("YOUR_TEXT_WITH_LINK").getFirstLinkBounds {
        (it.item as? LinkAnnotation.Url)?.url == "YOUR_URL"
    }

composeTestRule.onNodeWithText("YOUR_TEXT_WITH_LINK").performMouseInput {
    moveTo(firstLinkBounds!!.center)
}

getUnclippedBoundsInRoot

fun SemanticsNodeInteraction.getUnclippedBoundsInRoot(): DpRect

Returns the bounds of the layout of this node. The bounds are relative to the root composable.

invokeGlobalAssertions

@ExperimentalTestApi
fun SemanticsNodeInteraction.invokeGlobalAssertions(): SemanticsNodeInteraction

Executes all of the assertions registered by addGlobalAssertion. This may be useful in a custom test action.

Returns
SemanticsNodeInteraction

the SemanticsNodeInteraction that is the receiver of this method

performKeyPress

fun SemanticsNodeInteraction.performKeyPress(keyEvent: KeyEvent): Boolean

Send the specified KeyEvent to the focused component.

Returns
Boolean

true if the event was consumed. False otherwise.

printToLog

fun SemanticsNodeInteraction.printToLog(
    tag: String,
    maxDepth: Int = Int.MAX_VALUE
): Unit

Prints all the semantics nodes information into logs (as debug level).

By default this also prints all the sub-hierarchy. This can be changed by setting a custom max depth in maxDepth.

Note that this will fetch the latest snapshot of nodes it sees in the hierarchy for the IDs it collected before. So the output can change over time if the tree changes.

Parameters
tag: String

The tag to be used in the log messages.

maxDepth: Int = Int.MAX_VALUE

Max depth of the nodes in hierarchy to print. Zero will print just this node. Must not be negative.

printToString

fun SemanticsNodeInteraction.printToString(maxDepth: Int = Int.MAX_VALUE): String

Prints all the semantics nodes information it holds into string.

By default this also prints all the sub-hierarchy. This can be changed by setting a custom max depth in maxDepth.

Note that this will fetch the latest snapshot of nodes it sees in the hierarchy for the IDs it collected before. So the output can change over time if the tree changes.

Parameters
maxDepth: Int = Int.MAX_VALUE

Max depth of the nodes in hierarchy to print. Zero will print just this node. Must not be negative.

onAncestors

fun SemanticsNodeInteraction.onAncestors(): SemanticsNodeInteractionCollection

Returns all the ancestors of this node.

Example: For the following tree

|-A
|-B
|-C <- this node
Returns
B, A
fun SemanticsNodeInteraction.onChild(): SemanticsNodeInteraction

Returns exactly one child of this node.

Use this only if this node has exactly one child.

Any subsequent operation on its result will expect exactly one element found (unless SemanticsNodeInteraction.assertDoesNotExist is used) and will throw AssertionError if none or more than one element is found.

onChildAt

fun SemanticsNodeInteraction.onChildAt(index: Int): SemanticsNodeInteraction

Returns child of this node at the given index.

This is just a shortcut for "childrenindex".

onChildren

fun SemanticsNodeInteraction.onChildren(): SemanticsNodeInteractionCollection

Returns children of this node.

onParent

fun SemanticsNodeInteraction.onParent(): SemanticsNodeInteraction

Returns a parent of this node.

Any subsequent operation on its result will expect exactly one element found (unless SemanticsNodeInteraction.assertDoesNotExist is used) and will throw AssertionError if none or more than one element is found.

onSibling

fun SemanticsNodeInteraction.onSibling(): SemanticsNodeInteraction

Returns exactly one sibling of this node.

Use this only if this node has exactly one sibling.

Any subsequent operation on its result will expect exactly one element found (unless SemanticsNodeInteraction.assertDoesNotExist is used) and will throw AssertionError if none or more than one element is found.

onSiblings

fun SemanticsNodeInteraction.onSiblings(): SemanticsNodeInteractionCollection

Returns all siblings of this node.

Example: For the following tree

|-A
|-B1
|-B2 <- this node
|-B3
Returns
B1, B3

performImeAction

fun SemanticsNodeInteraction.performImeAction(): Unit

Sends to this node the IME action associated with it in a similar way to the IME.

The node needs to define its IME action in semantics via SemanticsPropertyReceiver.onImeAction.

Throws
kotlin.AssertionError

if the node does not support input or does not define IME action.

kotlin.IllegalStateException

if the node did is not an editor or would not be able to establish an input connection (e.g. does not define ImeAction or OnImeAction or is not focused).

performTextClearance

fun SemanticsNodeInteraction.performTextClearance(): Unit

Clears the text in this node in similar way to IME.

performTextInput

fun SemanticsNodeInteraction.performTextInput(text: String): Unit

Sends the given text to this node in similar way to IME.

Parameters
text: String

Text to send.

performTextInputSelection

@ExperimentalTestApi
fun SemanticsNodeInteraction.performTextInputSelection(
    selection: TextRange
): Unit

Sends the given selection to this node in similar way to IME.

Parameters
selection: TextRange

selection to send

performTextReplacement

fun SemanticsNodeInteraction.performTextReplacement(text: String): Unit

Replaces existing text with the given text in this node in similar way to IME.

This does not reflect text selection. All the text gets cleared out and new inserted.

Parameters
text: String

Text to send.