Skip to content

Compose

Aleksei Tiurin edited this page Aug 31, 2022 · 7 revisions

Android compose test looks smth like this:

class MyComposeTest {
    @get:Rule
    val composeTestRule = createComposeRule<YourActivity>()
    @Test
    fun myTest() {
        composeTestRule.setContent { .. } // if it's required
        composeTestRule.onNode(hasTestTag("Continue")).performClick()
        composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
    }
}

You can read more aboit it here

So, all compose api is provided by composeTestRule. It's definitely uncomfortable. Moreover in case your UI loading takes some time, e.g. in integration test, an assertion or an action fails.

Ultron compose framework solves all these problems and do a lot more.

Just create compose rule using Ultron static method

@get:Rule
val composeTestRule = createUltronComposeRule<YourActivity>()

After that you're able to perform stable compose operations in ANY class. Just create a SemanticsMatcher. e.g.

hasTestTag("Continue").click()
hasText("Welcome").assertIsDisplayed()

SemanticsMatcher object is used in android compose testing framework to find a target node to interact with.

Best practice

Specify page elements as properties of PageObject class.

object SomePage : Page<SomePage>() {
    private val button = hasTestTag(ComposeTestTags.button)
    private val eventStatus = hasTestTag(ComposeTestTags.eventStatus)
}

Here ComposeTestTags could be an object that stores testTag constants.

Use this properties in page steps

object SomePage : Page<SomePage>() {
    //page elements
    fun someUserStepOnPage(expectedEventText: String){
         button.click()
         eventStatus.assertTextContains(expectedEventText)
    }
}

Ultron supports standart compose API and provides additional operations.

//actions
fun click(option: ClickOption? = null)
fun clickCenterLeft(option: ClickOption? = null)
fun clickCenterRight(option: ClickOption? = null)
fun clickTopCenter(option: ClickOption? = null)
fun clickTopLeft(option: ClickOption? = null)
fun clickTopRight(option: ClickOption? = null)
fun clickBottomCenter(option: ClickOption? = null)
fun clickBottomLeft(option: ClickOption? = null)
fun clickBottomRight(option: ClickOption? = null)
fun longClick(option: LongClickOption? = null)
fun longClickCenterLeft(option: LongClickOption? = null)
fun longClickCenterRight(option: LongClickOption? = null)
fun longClickTopCenter(option: LongClickOption? = null)
fun longClickTopLeft(option: LongClickOption? = null)
fun longClickTopRight(option: LongClickOption? = null)
fun longClickBottomCenter(option: LongClickOption? = null)
fun longClickBottomLeft(option: LongClickOption? = null)
fun longClickBottomRight(option: LongClickOption? = null)
fun doubleClick(option: DoubleClickOption? = null)
fun doubleClickCenterLeft(option: DoubleClickOption? = null)
fun doubleClickCenterRight(option: DoubleClickOption? = null)
fun doubleClickTopCenter(option: DoubleClickOption? = null)
fun doubleClickTopLeft(option: DoubleClickOption? = null)
fun doubleClickTopRight(option: DoubleClickOption? = null)
fun doubleClickBottomCenter(option: DoubleClickOption? = null)
fun doubleClickBottomLeft(option: DoubleClickOption? = null)
fun doubleClickBottomRight(option: DoubleClickOption? = null)
fun swipeDown(option: ComposeSwipeOption? = null)
fun swipeUp(option: ComposeSwipeOption? = null)
fun swipeLeft(option: ComposeSwipeOption? = null)
fun swipeRight(option: ComposeSwipeOption? = null)
fun scrollTo()
fun scrollToIndex(index: Int)
fun scrollToKey(key: String)
fun scrollToNode(matcher: SemanticsMatcher)
fun imeAction()
fun pressKey(keyEvent: KeyEvent)
fun getText(): String?
fun inputText(text: String)
fun typeText(text: String)
fun inputTextSelection(selection: TextRange)
fun setSelection(startIndex: Int = 0, endIndex: Int = 0, traversalMode: Boolean)
fun selectText(range: TextRange)
fun clearText()
fun replaceText(text: String)
fun copyText()
fun pasteText()
fun cutText()
fun setText(text: String)
fun setText(text: AnnotatedString)
fun collapse()
fun expand()
fun dismiss()
fun setProgress(value: Float)
fun captureToImage(): ImageBitmap

fun performMouseInput(block: MouseInjectionScope.() -> Unit)
fun performSemanticsAction(key: SemanticsPropertyKey<AccessibilityAction<() -> Boolean>>) 
fun <T> perform(block: (SemanticsNodeInteraction) -> T, option: PerformCustomBlockOption? = null): T

//asserts
fun assertIsDisplayed()
fun assertIsNotDisplayed() 
fun assertExists()
fun assertDoesNotExist()
fun assertIsEnabled() 
fun assertIsNotEnabled() 
fun assertIsFocused() 
fun assertIsNotFocused() 
fun assertIsSelected() 
fun assertIsNotSelected()
fun assertIsSelectable()
fun assertIsOn() 
fun assertIsOff() 
fun assertIsToggleable() 
fun assertHasClickAction() 
fun assertHasNoClickAction() 
fun assertTextEquals(vararg expected: String, option: TextEqualsOption? = null)
fun assertTextContains(expected: String, option: TextContainsOption? = null)
fun assertContentDescriptionEquals(vararg expected: String)
fun assertContentDescriptionContains(expected: String, option: ContentDescriptionContainsOption? = null)
fun assertValueEquals(expected: String) 
fun assertRangeInfoEquals(range: ProgressBarRangeInfo)
fun assertHeightIsAtLeast(minHeight: Dp) 
fun assertHeightIsEqualTo(expectedHeight: Dp)
fun assertWidthIsAtLeast(minWidth: Dp) 
fun assertWidthIsEqualTo(expectedWidth: Dp) 
fun assertMatches(matcher: SemanticsMatcher, messagePrefixOnError: (() -> String)? = null)