CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-ui--ui-util-uikitsimarm64

iOS UIKit simulator ARM64 utilities for Compose Multiplatform UI framework providing testing, interoperability, and platform-specific implementations.

Pending
Overview
Eval results
Files

accessibility-testing.mddocs/

Accessibility Testing

iOS accessibility system integration with VoiceOver support, accessibility tree validation, and comprehensive testing utilities for ensuring app accessibility compliance.

Capabilities

Accessibility Tree Construction

Functions for building and analyzing the accessibility tree from the UI hierarchy.

/**
 * Constructs accessibility tree from current UI hierarchy
 * @return Root AccessibilityTestNode representing the complete accessibility tree
 */
internal fun UIKitInstrumentedTest.getAccessibilityTree(): AccessibilityTestNode

/**
 * Normalizes accessibility tree by removing non-essential elements
 * @return Normalized accessibility tree with only meaningful nodes, or null if empty
 */
internal fun AccessibilityTestNode.normalized(): AccessibilityTestNode?

Usage Example:

runUIKitInstrumentedTest {
    setContentWithAccessibilityEnabled {
        Column {
            Text("Welcome")
            Button(onClick = {}) {
                Text("Submit")
            }
        }
    }
    
    val tree = getAccessibilityTree()
    val normalizedTree = tree.normalized()
    
    println("Accessibility tree: $normalizedTree")
}

Accessibility Node Search

Functions for finding specific nodes within the accessibility tree based on various criteria.

/**
 * Finds accessibility node by identifier tag
 * @param tag - Identifier tag to search for
 * @return AccessibilityTestNode if found
 * @throws AssertionError if node with tag is not found
 */
internal fun UIKitInstrumentedTest.findNodeWithTag(tag: String): AccessibilityTestNode

/**
 * Finds accessibility node by accessibility label
 * @param label - Accessibility label to search for  
 * @return AccessibilityTestNode if found
 * @throws AssertionError if node with label is not found
 */
internal fun UIKitInstrumentedTest.findNodeWithLabel(label: String): AccessibilityTestNode

/**
 * Finds first accessibility element in the tree
 * @return AccessibilityTestNode of first accessible element
 * @throws AssertionError if no accessibility element is found
 */
internal fun UIKitInstrumentedTest.firstAccessibleNode(): AccessibilityTestNode

/**
 * Finds accessibility node matching a condition
 * @param isValid - Predicate function to test nodes
 * @return AccessibilityTestNode if found, null otherwise
 */
internal fun UIKitInstrumentedTest.findNodeOrNull(
    isValid: (AccessibilityTestNode) -> Boolean
): AccessibilityTestNode?

Usage Examples:

runUIKitInstrumentedTest {
    setContentWithAccessibilityEnabled {
        Button(
            onClick = {},
            modifier = Modifier.testTag("submit_button")
        ) {
            Text("Submit Form")
        }
    }
    
    // Find by test tag
    val submitButton = findNodeWithTag("submit_button")
    requireNotNull(submitButton) { "Submit button not found" }
    
    // Find by accessibility label
    val labeledNode = findNodeWithLabel("Submit Form")
    requireNotNull(labeledNode) { "Node with label not found" }
}

Accessibility Tree Validation

Comprehensive validation functions for asserting accessibility tree structure and content.

/**
 * Asserts that accessibility tree matches expected structure
 * @param block - DSL block defining expected tree structure
 * @throws AssertionError if tree structure doesn't match expectations
 */
fun UIKitInstrumentedTest.assertAccessibilityTree(
    block: AccessibilityTestNode.() -> Unit
)

Usage Example:

runUIKitInstrumentedTest {
    setContentWithAccessibilityEnabled {
        Column {
            Text("Header Text")
            Row {
                Text("Label:")
                Text("Value")
            }
            Button(onClick = {}) {
                Text("Action")
            }
        }
    }
    
    assertAccessibilityTree {
        node {
            label = "Header Text"
            children = listOf(
                node {
                    label = "Label:"
                    children = listOf(
                        node { label = "Value" }
                    )
                },
                node {
                    label = "Action"
                    role = "button"
                }
            )
        }
    }
}

Accessibility Node Interactions

Functions for interacting with accessibility nodes through accessibility actions.

/**
 * Simulates tap on accessibility element using accessibility actions
 * @throws IllegalStateException if node is not accessible or tappable
 */
fun AccessibilityTestNode.tap()

/**
 * Simulates double tap on accessibility element
 * @throws IllegalStateException if node doesn't support double tap action
 */
fun AccessibilityTestNode.doubleTap()

Usage Examples:

runUIKitInstrumentedTest {
    setContentWithAccessibilityEnabled {
        Button(onClick = { println("Button clicked!") }) {
            Text("Click Me")
        }
    }
    
    val button = findNodeWithLabel("Click Me")
    requireNotNull(button) { "Button not found" }
    
    // Tap using accessibility action
    button.tap()
    
    // Double tap if supported  
    button.doubleTap()
}

AccessibilityTestNode Data Class

Represents a node in the accessibility tree with comprehensive accessibility information.

/**
 * Represents a node in the accessibility tree for testing purposes
 * @param isAccessibilityElement - Whether element is exposed to accessibility services
 * @param identifier - Unique identifier for the accessibility element
 * @param label - Accessibility label for VoiceOver
 * @param value - Current value of the accessibility element
 * @param frame - Bounding rectangle in screen coordinates
 * @param children - Child accessibility nodes
 * @param traits - Accessibility traits as UIAccessibilityTraits values
 * @param element - Reference to the underlying NSObject
 * @param parent - Parent accessibility node
 */
internal data class AccessibilityTestNode(
    var isAccessibilityElement: Boolean? = null,
    var identifier: String? = null,
    var label: String? = null,
    var value: String? = null,
    var frame: DpRect? = null,
    var children: List<AccessibilityTestNode>? = null,
    var traits: List<UIAccessibilityTraits>? = null,
    var element: NSObject? = null,
    var parent: AccessibilityTestNode? = null
) {
    fun validate(actualNode: AccessibilityTestNode?)
    fun node(builder: AccessibilityTestNode.() -> Unit)
    fun traits(vararg trait: UIAccessibilityTraits)
    fun printTree(): String
    val hasAccessibilityComponents: Boolean
}

Usage Example:

val node = AccessibilityTestNode(
    identifier = "user_profile_button",
    label = "User Profile",
    hint = "Double tap to open profile",
    role = "button",
    traits = setOf("button", "enabled"),
    frame = DpRect(
        offset = DpOffset(10.dp, 10.dp),
        size = DpSize(100.dp, 44.dp)
    )
)

Advanced Accessibility Testing Patterns

Testing Complex UI Hierarchies

runUIKitInstrumentedTest {
    setContentWithAccessibilityEnabled {
        NavigationView {
            List {
                ForEach(items) { item ->
                    NavigationLink(destination = DetailView(item)) {
                        VStack {
                            Text(item.title)
                            Text(item.subtitle)
                        }
                    }
                }
            }
        }
    }
    
    assertAccessibilityTree {
        node {
            role = "list"
            children = items.map { item ->
                node {
                    label = item.title
                    role = "button"
                    traits = setOf("button", "link")
                    children = listOf(
                        node { label = item.subtitle }
                    )
                }
            }
        }
    }
}

Testing Dynamic Content Updates

runUIKitInstrumentedTest {
    var counter by remember { mutableStateOf(0) }
    
    setContentWithAccessibilityEnabled {
        Column {
            Text("Count: $counter")
            Button(onClick = { counter++ }) {
                Text("Increment")
            }
        }
    }
    
    // Test initial state
    val initialCount = findNodeWithLabel("Count: 0")
    requireNotNull(initialCount)
    
    // Interact and test updated state
    val button = findNodeWithLabel("Increment")
    button?.tap()
    
    waitUntil {
        findNodeWithLabel("Count: 1") != null
    }
}

VoiceOver Integration

  • Full VoiceOver Support: Complete integration with iOS VoiceOver screen reader
  • Focus Management: Proper accessibility focus handling and navigation
  • Announcements: Support for dynamic accessibility announcements
  • Custom Actions: Integration with custom accessibility actions
  • Grouping: Proper accessibility element grouping and container support

Error Handling

  • AssertionError: Thrown when accessibility tree assertions fail
  • IllegalStateException: Thrown when attempting to interact with inaccessible elements
  • TimeoutException: Thrown when waiting for accessibility tree changes times out
  • Graceful Degradation: Fallback behaviors when accessibility services are disabled

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-compose-ui--ui-util-uikitsimarm64

docs

accessibility-testing.md

coordinate-utilities.md

index.md

ios-uikit-testing.md

touch-simulation.md

tile.json