In Jetpack compose I have a TextField and I'm trying to write Espresso UI tests.
I didn't find how I can enter text in the TextField, any ideas, please?
TextField(
value = textState.value,
modifier = Modifier.fillMaxWidth(),
onValueChange = {
textState.value = it
apiServiceCall(textState.value.text)
},
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences)
),
)
@get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Test
fun enterTextAndMakeServiceCall() {
ActivityScenario.launch(MainActivity::class.java)
// TODO: Enter text inside the TextField
composeTestRule.onNode(hasText(getString(R.string.result)))
}
I first set the testTag
modifier on the composable I want to test:
const val MY_TEXTFIELD_TAG = "myTextFieldTag"
TextField(
value = textState.value,
modifier = Modifier.fillMaxWidth().testTag(MY_TEXTFIELD_TAG),
onValueChange = {
textState.value = it
},
keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
)
And then from your test you can set and check the value like this:
@Test
fun setAndCheckTheTextFieldValue() {
ActivityScenario.launch(MainActivity::class.java)
val resultText = "result"
// Sets the TextField value
composeTestRule.onNodeWithTag(MY_TEXTFIELD_TAG).performTextInput(resultText)
// Asserts the TextField has the corresponding value
composeTestRule.onNodeWithTag(MY_TEXTFIELD_TAG).assert(hasText(resultText))
}
UPDATE:
Another way I use lately is to use the contentDescription
instead.
Let's say you have a TextField with content description like this one (not using state hoisting for simplicity on this sample):
@Composable
fun MyTextField() {
val textState = remember { mutableStateOf(TextFieldValue()) }
val textFieldContentDescription = stringResource(id = R.string.text_field_content_description)
TextField(
value = textState.value,
modifier = Modifier
.fillMaxWidth()
.semantics { contentDescription = textFieldContentDescription },
onValueChange = {
textState.value = it
},
)
}
The test could be something like:
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun setAndCheckTheTextFieldValue() {
lateinit var textFieldContentDescription: String
composeTestRule.setContent {
textFieldContentDescription = stringResource(id = R.string.text_field_content_description)
MaterialTheme {
MyTextField()
}
}
val resultText = "result"
// Sets the TextField value
composeTestRule.onNodeWithContentDescription(textFieldContentDescription).performTextInput(resultText)
// Asserts the TextField has the corresponding value
composeTestRule.onNodeWithContentDescription(textFieldContentDescription).assert(hasText(resultText, ignoreCase = true))
}
and this way the app is more accessible as well by having content descriptions.