我在 compose 的内置 TextField 上有这个包装器
MyInput
,它执行一系列 UI 操作,并为应用程序中的所有输入声明全局样式。
我将所有组件放入
ui
模块中,然后从不同的屏幕上使用它。
问题是当我尝试进行 UI 测试并执行
performTextInput("[email protected]")
时,如下所示:
composeTestRule.onNodeWithTag("enter_email_field")
.assertIsDisplayed()
.performTextInput("[email protected]")
我得到以下结果:
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')
我的自定义
MyInput
是否可以支持这些语义?我尝试阅读 TextField
的源代码,但我看不到它是在哪里声明的?
为了使自定义 MyInput 可组合项支持 UI 测试所需的语义,您需要确保它正确提供文本输入所需的语义属性。您遇到的问题表明您的自定义组件未正确公开 PerformTextInput 函数工作所需的 SetText 操作。
以下是如何将所需的语义添加到自定义 MyInput 组件中:
1。确保 Modifier.semantics 设置正确: 确保您的自定义可组合项应用适当的语义修饰符。
2。公开 TextField 语义: 由于您的 MyInput 包装了 TextField,因此您需要确保 TextField 的语义不会被其他组件覆盖或阻止。
这是一个基本示例,说明如何构建 MyInput 以确保它公开所需的语义:
@Composable
fun MyInput(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
testTag: String = ""
) {
Box(
modifier = modifier
.testTag(testTag)
.semantics { // Ensure semantics are correctly set
contentDescription = testTag
}
) {
TextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier.fillMaxWidth()
)
}
}
在您的测试中,您将使用:
composeTestRule.onNodeWithTag("enter_email_field")
.assertIsDisplayed()
.performTextInput("[email protected]")
关键部分是确保通过自定义 MyInput 组件保留并公开 TextField 的语义。 .semantics {} 块用于定义或扩展语义属性,并使用 Modifier.testTag(testTag) 确保测试框架可以找到该节点。
如果您需要更多自定义语义,或者 TextField 被包装在其他可能会掩盖其语义的组件中,您可能需要根据需要显式传递或设置这些语义。
调试语义
要调试节点上当前可用的语义,您可以在测试期间打印出节点的语义:
composeTestRule.onNodeWithTag("enter_email_field")
.printToLog("Semantics")
这可以帮助您了解是否正确设置了必要的语义(如 SetText)以及它们是否可访问。
高级语义示例
如果您的组件更复杂并且涉及额外的层,您可能需要确保语义正确转发:
@Composable
fun MyInput(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
testTag: String = ""
) {
Box(
modifier = modifier
.testTag(testTag)
.semantics { // Adding semantics directly
text = AnnotatedString(value)
setText = { newText ->
onValueChange(newText)
true
}
}
) {
TextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier.fillMaxWidth().semantics(mergeDescendants = true) {}
)
}
}
在这个例子中,text和setText语义直接添加到包含TextField的Box中,这保证了TextField仍然可以正确交互。
通过正确管理和公开这些语义,您的自定义 MyInput 可组合项应该支持所需的测试操作。