Blog Infos
Author
Published
Topics

This article will explore how the Accessibility Testing Framework (ATF) can automate accessibility-related checks for Compose-based UIs.
Starting with Compose version 1.8.0 We got support for Compose to perform accessibility checks in our UI tests automatically.
Enabling accessibility checks is currently only supported for
AndroidComposeTestRule.
Required dependencies
- Add the following dependencies to the version catalog
libs.versions.toml file and then add it to your module’s
build.gradle file or directly add to the module’s
build.gradle
[versions] composeBom = "2025.05.01" uiTestJunit4Accessibility = "1.9.0-alpha03" uiTestManifest = "1.9.0-alpha03" [libraries] androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4-accessibility", version.ref = "uiTestJunit4Accessibility" } ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "uiTestManifest" }
App-level build file
androidTestImplementation(libs.androidx.ui.test.junit4.accessibility) // Needed for createComposeRule() debugImplementation(libs.ui.test.manifest)
Let’s write a UI test that includes accessibility checks ♿️
Composable
We have a UI with three components:
- Text —
Login sample screen
- Text —
Submit
- Icon — 🧳
@Composable fun LoginScreen(modifier: Modifier = Modifier) { Column( modifier = modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text("Login sample screen") SubmitCTA() // .... } } @Composable fun SubmitCTA(modifier: Modifier = Modifier) { Row( horizontalArrangement = Arrangement.Center ) { Text( "Submit", // Set the color intentionally - color contrast issue style = MaterialTheme.typography.labelSmall.copy( color = Color.Gray ) ) } }
Compose Preview
Enable accessibility checks on the Compose test rule
class ComposeUISampleTest { @get:Rule val composeTestRule = createComposeRule() @Before fun setUp() { // Enable accessibility checks with default configuration: composeTestRule.enableAccessibilityChecks() } // ....
- After enabling the checks, they will automatically run when we perform
actions.
class ComposeUISampleTest { @get:Rule val composeTestRule = createComposeRule() @Before fun setUp() { // Enable accessibility checks with default configuration: composeTestRule.enableAccessibilityChecks() } @Test fun testSubmitAction() { composeTestRule.setContent { LoginScreen() } // Accessibility checks run automatically when performing an action: composeTestRule.onNodeWithText("Submit").performClick() }
- When we run the test, it fails with the following logs ⧰😨
🛑 Text contrast ratio check fails for Submit text
com.google.android.apps.common.testing.accessibility.framework.integrations.espresso.AccessibilityViewCheckException: There was 1 accessibility result: View with bounds: [161,190][258,232]: The item's text contrast ratio is 3.40. This ratio is based on an estimated foreground color of #888888 and an estimated background color of #FAFAFA. Consider using colors that result in a contrast ratio greater than 4.50 for small text, or 3.00 for large text.
Let’s test another case — Content description
Composable
@Composable fun LoginScreen(modifier: Modifier = Modifier) { Column { // ... // Missing content description Icon( Icons.Outlined.Work, contentDescription = "" ) } }

Compose Preview
- Test code stays the same in this case; When we rerun the test, we see the following logs
🛑 Missing content description for the work icon 🧳
com.google.android.apps.common.testing.accessibility.framework.integrations.espresso.AccessibilityViewCheckException: There was 1 accessibility result: View with bounds: [178,274][241,337]: This item may not have a label readable by screen readers. Reported by com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck
Enable AccessibilityChecks with a custom validator
- By default, when we enable the checks, it uses the default validator
public fun ComposeTestRule.enableAccessibilityChecks( accessibilityValidator: AccessibilityValidator = AccessibilityValidator().setRunChecksFromRootView(true) ) { // .....
- As you can see in the above code snippet,
enableAccessibilityChecks take an
AccessibilityValidator as a param. So if we want to customize the behavior, we can pass our custom validator.
- The default implementation of AccessibilityValidator throws an exception for any Error.
- Let’s say we want to throw an exception for 🛑
Error and ⚠️
Warning. In this case, we need to provide a custom validator.
Custom AccessibilityValidator implementation
val accessibilityValidator = AccessibilityValidator().apply { setThrowExceptionFor(AccessibilityCheckResult.AccessibilityCheckResultType.WARNING) }
And then use this validator with enableAccessibilityChecks
class ComposeUISampleTest { @get:Rule val composeTestRule = createComposeRule() @Before fun setUp() { // Enable accessibility checks with custom validator composeTestRule.enableAccessibilityChecks( accessibilityValidator = accessibilityValidator) // ...
- Now, if there is any accessibility related warning or error, our test will throw an exception.
Job Offers
Perform accessibility checks manually
- We can use
tryPerformAccessibilityChecks() to perform accessibility checks manually
class ComposeUISampleTest { @Test fun testSubmitCTAAction() { // You can also manually run accessibility checks: composeTestRule.onRoot().tryPerformAccessibilityChecks() }
Disable accessibility checks
- We can use
disableAccessibilityChecks() to disable the accessibility checks
class ComposeUISampleTest { @Test fun disableChecksSample() { // disabling accessibility checks.. composeTestRule.disableAccessibilityChecks() }
Let’s make Android applications more accessible
Stay in touch
References
This article was previously published on proandroiddev.com.