Allow custom TextInput wrapper to support UI testing `performTextInput`
I have this wrapper MyInput
over compose's builtin TextField that does a series of UI operations and declares a style globally for all my inputs in the app.
I put all my components in a ui
module and then I consume it from my different screens.
The problem is when I try to do UI testing and execute performTextInput("[email protected]")
like so:
composeTestRule.onNodeWithTag("enter_email_field")
.assertIsDisplayed()
.performTextInput("[email protected]")
and I get the following result:
java.lang.AssertionError: Failed to perform text input.
Failed to assert the following: (SetText is defined)
Semantics of the node:
Node #20 at (l=84.0, t=1500.0, r=1356.0, b=1699.0)px, Tag: 'enter_email_field'
Has 1 child, 10 siblings
Selector used: (TestTag = 'enter_email_field')
Would it be possible to have my custom MyInput
support these semantics? I tried reading the source for TextField
but I fail to see where this is declared?
if i declare the semantics for setText myself i am asked for requestFocus
and then insertTextAtCursor
? Id like to just inherit these from the inner BasicTextField
Answer
If your custom TextInput wrapper has TextField as a child of some other composable you should first get the child TextField and then perform text input on it.
composeTestRule.onNodeWithTag("enter_email_field")
.onChildren()
.filterToOne(hasSetTextAction())
.performTextInput("[email protected]")
You can create a helper function to avoid repetition.
fun SemanticsNodeInteraction.editTextNode() = onChildren().filterToOne(hasSetTextAction())
Previous Answer
If you want your custom text field to support performTextInput
; make sure you are supplying the test tag on the inner TextField
's Modifier.
This will work
@Composable
fun MyTextField(
modifier: Modifier,
testTag: String,
) {
var text by remember { mutableStateOf("Initial") }
Box(modifier) {
TextField(text, { text = it }, Modifier.testTag(testTag))
}
}
This won't
@Composable
fun MyTextField(
modifier: Modifier,
testTag: String,
) {
var text by remember { mutableStateOf("Initial") }
Box(modifier.testTag(testTag)) {
TextField(text, { text = it }, Modifier)
}
}