如何通过 UI 测试在 Jetpack compose TextField 中输入文本?

How to enter text in Jetpack compose TextField through UI tests?

在 Jetpack compose 中,我有一个 TextField,我正在尝试编写 Espresso UI 测试。
我没有找到如何在 TextField 中输入文本,请问有什么想法吗?

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)))
}

我首先在我要测试的可组合项上设置 testTag 修饰符:

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),
)

然后从您的测试中您可以像这样设置和检查值:

@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))
}

更新:

我最近使用的另一种方法是改用 contentDescription

假设您有一个 TextField,其内容描述如下(为简单起见,在此示例中未使用状态提升):

@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
        },
    )
}

测试可能是这样的:

@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))
}

通过这种方式,通过内容描述,应用程序也更易于访问。

你可以通过 nodeText 找到你需要在 label 属性

中搜索的字符串
composeTestRule.onNodeWithText("user").performTextInput("userCred")

这将找到该文本字段并输入文本“userCred”。

此解决方案仅在您没有与该字符串匹配的任何其他文本时才有效。