https://kotlinlang.org logo
#compose
Title
# compose
p

Peter Mandeljc

02/06/2023, 10:37 AM
are there any best practices, how to test custom components in Compose? I have a custom
MyTextField
composable and I would like somehow send text directly to the root of it. Atm I'm getting
Failed to assert the following: (SetText is defined)
.
For example, if I have following composable:
Copy code
@Composable
fun MyTextField(...) {
    Box {
        Column {
            Row {
                BasicTextField(...)
            }
        }
    }
}
And use it like so:
Copy code
@Composable
fun SomeScreen() {
   MyTextField(modifier = Modifiler.testTag("myTextField"))
}
Is it possible to send text to root of it like this:
Copy code
// instrumented unit test
composeRule.onNodeWithTag("myTextField").performTextInput("banana")
Can I avoid having utility functions, that matches exactly the composable inside
MyTextField
(
BasicTextField
)?
Or if I ask a bit differently... how does compose test framework know, on which child composable to set text, when
performTextInput
is called on material
TextField
for example?
a

Alex Vanyo

02/06/2023, 7:04 PM
I’d take a look at
.semantics(mergeDescendants = true)
and the overall documentation for semantics: https://developer.android.com/jetpack/compose/semantics Even though you asked about testing, the test tools use the same semantic information that drives accessibility services. If you’re making a custom component, tweaking the semantics of it to work naturally with the test tools should go hand-in-hand to making sure the custom component works well with accessibility services too!
p

Peter Mandeljc

02/06/2023, 7:32 PM
That seems exactly what I'm missing. Thanks!
l

Lorenzo Neumann

07/07/2023, 2:38 PM
@Peter Mandeljc Hey, did you find a solution yet? The mergeDescendants approach does not yet work for me and I ended up setting the testTag as parameter on the composable and then use it on the text field itself.
p

Peter Mandeljc

07/07/2023, 2:46 PM
Not sure if it's completely correct, but I did the following
Copy code
modifier.semantics(
    mergeDescendanta = true,
    properties = {
        setText {
            onTextChanged(it.text),
            true
        }
    }
)
l

Lorenzo Neumann

07/07/2023, 3:20 PM
Yeah, that also came to my mind, but with that the semantics of all composables are merged which I don't want as I also use buttons and images as siblings to my text field. But nervertheless, thanks!
p

Peter Mandeljc

07/07/2023, 4:23 PM
I think you can still set
mergeDescendants = false
?
l

Lorenzo Neumann

07/10/2023, 7:36 AM
That all did not work out the way I needed. I now ended up reworking my custom text field to only use the BasicTextField with a custom decoration box so that semantics are handled as with a normal text field.
160 Views