Search code examples
androidandroid-jetpack-composeappium

Android compose Modifier extension does not work with testTagsAsResourceId


We need to add id so people from QA can use Appium Inspector, this works:

Text(
    modifier = Modifier
        .semantics { this.testTagsAsResourceId = true }
        .testTag("someId"),
    text = "Something"
)               

The problem is repeating those two lines on every composable that needs it, is tedious

.semantics { this.testTagsAsResourceId = true }
.testTag("someId")

So creating an extension for Modifier could be the solution:

@OptIn(ExperimentalComposeUiApi::class)
fun Modifier.setTagAndId(tag: String): Modifier = composed {
    semantics { this.testTagsAsResourceId = true }
    testTag(tag)
}

When running Appium Inpsector the ids are not there, if instead replace the extension for the two lines directly in the composable, I can see the ids.

Writing the extension in other way does not work neither

fun Modifier.setTagAndId(tag: String): Modifier {
    semantics { this.testTagsAsResourceId = true }
    testTag(tag)
    return this
}

The above introduces another problem, the testTag is not found by Espresso, so that is another reason to discard it.

Changing the experimental annotation to propagate and then opt-in in the composable neither works:

@ExperimentalComposeUiApi
fun Modifier.setTagAndId(tag: String): Modifier {
...
}

Reading the composed documentation the first argument is the InspectorInfo, so I tried to abide to that:

fun Modifier.setTagAndId(tag: String): Modifier = composed(
    inspectorInfo = {
        name = "TestTagsAsResourceId" //got the name from testTagsAsResourceId file
        value = tag
    }
) {
    ...
}

But it doesn't work.

I have created extensions for Modifier using composed as well, so after all the attempts I don't understand why is not working with testTagsAsResourceId.

How to create an extension for Modifier to set the semantics property testTagsAsResourceId?


Solution

  • This should work

    
    @OptIn(ExperimentalComposeUiApi::class)
    fun Modifier.setTagAndId(tag: String): Modifier {
        return this
            .semantics { this.testTagsAsResourceId = true }
            .testTag(tag)
    }
    

    Btw you don't need to set testTagsAsResourceId on every resource that you need a testTag. Only on the root composable (And dialogs) see https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/package-summary#(androidx.compose.ui.semantics.SemanticsPropertyReceiver).testTagsAsResourceId()