ComposeTestRule

Known direct subclasses
ComposeContentTestRule

A ComposeTestRule that allows you to set content without the necessity to provide a host for the content.


A TestRule that allows you to test and control composables, either in isolation or in applications. Most of the functionality in this interface provides some form of test synchronization: the test will block until the app or composable is idle, to ensure the tests are deterministic.

For example, if you would perform a click on the center of the screen while a button is animating from left to right over the screen, without synchronization the test would sometimes click when the button is in the middle of the screen (button is clicked), and sometimes when the button is past the middle of the screen (button is not clicked). With synchronization, the app would not be idle until the animation is over, so the test will always click when the button is past the middle of the screen (and not click it). If you actually do want to click the button when it's in the middle of the animation, you can do so by controlling the clock. You'll have to disable automatic advancing, and manually advance the clock by the time necessary to position the button in the middle of the screen.

An instance of ComposeTestRule can be created with createComposeRule, which will also create a host for the compose content for you (see ComposeContentTestRule). If you need to specify which particular Activity is started on Android, you can use createAndroidComposeRule.

If you don't want any Activity to be started automatically by the test rule on Android, you can use createEmptyComposeRule. In such a case, you will have to set content using one of Compose UI's setters (like androidx.compose.ui.platform .setContent).

Summary

Public functions

suspend Unit

Suspends until the UI is idle.

android
open Unit

Disables accessibility checks.

android
open Unit

Enables accessibility checks that will be run before every action that is expected to change the UI.

android
Unit

Registers an IdlingResource in this test.

android
T
<T : Any?> runOnIdle(action: () -> T)

Executes the given action in the same way as runOnUiThread but waits until the app is idle before executing the action.

android
T
<T : Any?> runOnUiThread(action: () -> T)

Runs the given action on the UI thread.

android
Unit

Unregisters an IdlingResource from this test.

android
Unit

Waits for the UI to become idle.

android
Unit
waitUntil(timeoutMillis: Long, condition: () -> Boolean)

Blocks until the given condition is satisfied.

android
open Unit
waitUntil(
    conditionDescription: String,
    timeoutMillis: Long,
    condition: () -> Boolean
)

Blocks until the given condition is satisfied.

android
Unit

Blocks until at least one node matches the given matcher.

android
Unit

Blocks until no nodes match the given matcher.

android
Unit

Blocks until exactly one node matches the given matcher.

android
Unit
@ExperimentalTestApi
waitUntilNodeCount(
    matcher: SemanticsMatcher,
    count: Int,
    timeoutMillis: Long
)

Blocks until the number of nodes matching the given matcher is equal to the given count.

android

Public properties

Density

Current device screen's density.

android
MainTestClock

Clock that drives frames and recompositions in compose tests.

android

Inherited functions

From androidx.compose.ui.test.SemanticsNodeInteractionsProvider
SemanticsNodeInteractionCollection
onAllNodes(matcher: SemanticsMatcher, useUnmergedTree: Boolean)

Finds all semantics nodes that match the given condition.

android
SemanticsNodeInteraction
onNode(matcher: SemanticsMatcher, useUnmergedTree: Boolean)

Finds a semantics node that matches the given condition.

android
From org.junit.rules.TestRule
Statement
android

Public functions

awaitIdle

suspend fun awaitIdle(): Unit

Suspends until the UI is idle. Quiescence is reached when there are no more pending changes (e.g. pending recompositions or a pending draw call) and all IdlingResources are idle.

If auto advancement is enabled on the mainClock, this method will advance the clock to process any pending composition, invalidation and animation. If auto advancement is not enabled, the clock will not be advanced which means that the Compose UI appears to be frozen. This is ideal for testing animations in a deterministic way. This method will always wait for all IdlingResources to become idle.

Note that some processes are driven by the host operating system and will therefore still execute when auto advancement is disabled. For example, Android's measure, layout and draw passes can still happen if required by the View system.

disableAccessibilityChecks

@RequiresApi(value = 34)
open fun disableAccessibilityChecks(): Unit

Disables accessibility checks.

// Enable accessibility checks with your own AccessibilityValidator:
androidComposeTestRule.accessibilityValidator = AccessibilityValidator()
// By setting a non-null AccessibilityValidator, accessibility checks are enabled

// Configure the AccessibilityValidator:
androidComposeTestRule.accessibilityValidator!!.setThrowExceptionFor(
    AccessibilityCheckResultType.ERROR
)

enableAccessibilityChecks

@RequiresApi(value = 34)
open fun enableAccessibilityChecks(): Unit

Enables accessibility checks that will be run before every action that is expected to change the UI.

Accessibility checks are platform dependent, refer to the documentation of the platform specific variant of ComposeTestRule to see if it is supported and how you can configure it.

On Android, this requires API 34+ (Android U), and currently does not work on Robolectric.

import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollToIndex
import androidx.compose.ui.test.tryPerformAccessibilityChecks

// Enable accessibility checks with default configuration:
composeTestRule.enableAccessibilityChecks()

// Accessibility checks are run automatically when performing an action:
composeTestRule.onNodeWithText("Submit").performClick()

// You can also manually run accessibility checks:
composeTestRule.onRoot().tryPerformAccessibilityChecks()

// When disabling accessibility checks..
composeTestRule.disableAccessibilityChecks()

// .. they no longer run when performing an action:
composeTestRule.onNodeWithTag("list").performScrollToIndex(15)

registerIdlingResource

fun registerIdlingResource(idlingResource: IdlingResource): Unit

Registers an IdlingResource in this test.

runOnIdle

fun <T : Any?> runOnIdle(action: () -> T): T

Executes the given action in the same way as runOnUiThread but waits until the app is idle before executing the action. This is the recommended way of doing your assertions on shared variables.

This method blocks until the action is complete.

runOnUiThread

fun <T : Any?> runOnUiThread(action: () -> T): T

Runs the given action on the UI thread.

This method is blocking until the action is complete.

unregisterIdlingResource

fun unregisterIdlingResource(idlingResource: IdlingResource): Unit

Unregisters an IdlingResource from this test.

waitForIdle

fun waitForIdle(): Unit

Waits for the UI to become idle. Quiescence is reached when there are no more pending changes (e.g. pending recompositions or a pending draw call) and all IdlingResources are idle.

If auto advancement is enabled on the mainClock, this method will advance the clock to process any pending composition, invalidation and animation. If auto advancement is not enabled, the clock will not be advanced which means that the Compose UI appears to be frozen. This is ideal for testing animations in a deterministic way. This method will always wait for all IdlingResources to become idle.

Note that some processes are driven by the host operating system and will therefore still execute when auto advancement is disabled. For example, Android's measure, layout and draw passes can still happen if required by the View system.

waitUntil

fun waitUntil(timeoutMillis: Long, condition: () -> Boolean): Unit

Blocks until the given condition is satisfied.

If auto advancement is enabled on the mainClock, this method will actively advance the clock to process any pending composition, invalidation and animation. If auto advancement is not enabled, the clock will not be advanced actively which means that the Compose UI appears to be frozen. It is still valid to use this method in this way, if the condition will be satisfied by something not driven by our clock.

Compared to MainTestClock.advanceTimeUntil, waitUntil sleeps after every iteration to yield to other processes. This gives waitUntil a better integration with the host, but it is less preferred from a performance viewpoint. Therefore, we recommend that you try using MainTestClock.advanceTimeUntil before resorting to waitUntil.

Parameters
timeoutMillis: Long

The time after which this method throws an exception if the given condition is not satisfied. This observes wall clock time, not test clock time.

condition: () -> Boolean

Condition that must be satisfied in order for this method to successfully finish.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If the condition is not satisfied after timeoutMillis (in wall clock time).

waitUntil

open fun waitUntil(
    conditionDescription: String,
    timeoutMillis: Long,
    condition: () -> Boolean
): Unit

Blocks until the given condition is satisfied.

If auto advancement is enabled on the mainClock, this method will actively advance the clock to process any pending composition, invalidation and animation. If auto advancement is not enabled, the clock will not be advanced actively which means that the Compose UI appears to be frozen. It is still valid to use this method in this way, if the condition will be satisfied by something not driven by our clock.

Compared to MainTestClock.advanceTimeUntil, waitUntil sleeps after every iteration to yield to other processes. This gives waitUntil a better integration with the host, but it is less preferred from a performance viewpoint. Therefore, we recommend that you try using MainTestClock.advanceTimeUntil before resorting to waitUntil.

Parameters
conditionDescription: String

An optional human-readable description of condition that will be included in the timeout exception if thrown.

timeoutMillis: Long

The time after which this method throws an exception if the given condition is not satisfied. This observes wall clock time, not test clock time.

condition: () -> Boolean

Condition that must be satisfied in order for this method to successfully finish.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If the condition is not satisfied after timeoutMillis (in wall clock time).

waitUntilAtLeastOneExists

@ExperimentalTestApi
fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeoutMillis: Long): Unit

Blocks until at least one node matches the given matcher.

Parameters
matcher: SemanticsMatcher

The matcher that will be used to filter nodes.

timeoutMillis: Long

The time after which this method throws an exception if no nodes match the given matcher. This observes wall clock time, not frame time.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If no nodes match the given matcher after timeoutMillis (in wall clock time).

See also
waitUntil

waitUntilDoesNotExist

@ExperimentalTestApi
fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeoutMillis: Long): Unit

Blocks until no nodes match the given matcher.

Parameters
matcher: SemanticsMatcher

The matcher that will be used to filter nodes.

timeoutMillis: Long

The time after which this method throws an exception if any nodes match the given matcher. This observes wall clock time, not frame time.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If any nodes match the given matcher after timeoutMillis (in wall clock time).

See also
waitUntil

waitUntilExactlyOneExists

@ExperimentalTestApi
fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeoutMillis: Long): Unit

Blocks until exactly one node matches the given matcher.

Parameters
matcher: SemanticsMatcher

The matcher that will be used to filter nodes.

timeoutMillis: Long

The time after which this method throws an exception if exactly one node does not match the given matcher. This observes wall clock time, not frame time.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If exactly one node does not match the given matcher after timeoutMillis (in wall clock time).

See also
waitUntil

waitUntilNodeCount

@ExperimentalTestApi
fun waitUntilNodeCount(
    matcher: SemanticsMatcher,
    count: Int,
    timeoutMillis: Long
): Unit

Blocks until the number of nodes matching the given matcher is equal to the given count.

Parameters
matcher: SemanticsMatcher

The matcher that will be used to filter nodes.

count: Int

The number of nodes that are expected to

timeoutMillis: Long

The time after which this method throws an exception if the number of nodes that match the matcher is not count. This observes wall clock time, not frame time.

Throws
androidx.compose.ui.test.ComposeTimeoutException

If the number of nodes that match the matcher is not count after timeoutMillis (in wall clock time).

See also
waitUntil

Public properties

density

val densityDensity

Current device screen's density. Note that it is technically possible for a Compose hierarchy to define a different density for a certain subtree.

mainClock

val mainClockMainTestClock

Clock that drives frames and recompositions in compose tests.