Hey folks! I am only seriously starting to test my...
# compose
d
Hey folks! I am only seriously starting to test my composables (yeah, I know, shame on me... 😛). I am using a lot of
onChild()
to traverse the descendants of an already captured node (with the root
onNode()
selector methods or friends). This seems very brittle to me as it asserts a lot about the Composable semantic tree structure. I feel I am missing some way to capture descendants of an already captured node. I will add an example of one of my tests in the thread. I will be very glad if some could comment out on how I should enhance the reliability of this test.
The composable under test:
Copy code
@Composable
fun PersonaSelector(
    label: String? = i18n.roleplay.personaLabel,
    selectedPersona: Persona,
    onPersonaSelected: (Persona) -> Unit,
    personas: List<Persona>,
    modifier: Modifier = Modifier,
) {
    GenericSelector(
        modifier = modifier,
        label = label,
        selectedItem = selectedPersona,
        onSelectItem = onPersonaSelected,
        options = personas,
        itemLabeler = { it.name },
        itemOption = {
            Row(verticalAlignment = Alignment.CenterVertically) {
                AssistChip(
                    modifier = Modifier.padding(end = 8.dp),
                    label = { Text(text = it.nickname, style = MaterialTheme.typography.bodySmall) },
                    enabled = false,
                    onClick = {},
                )

                Text(text = it.name, maxLines = 1, overflow = TextOverflow.Ellipsis)
            }
        },
    )
}
The test content:
Copy code
val personas = listOf(
            Persona("Robert", "Bob"),
            Persona("Nikita", "Niky"),
            Persona("Dorothy", "Dottie")
        )
        val selectedPersona = personas.first()

        setContent {
            PersonaSelector(
                modifier = Modifier.testTag("selector"),
                label = "Persona",
                selectedPersona = selectedPersona,
                onPersonaSelected = { },
                personas = personas,
            )
        }

        val selector = onNodeWithTag("selector")
        selector.onChild().assertTextContains("Persona")

        val popup = onNode(isPopup())
        popup.assertDoesNotExist()

        selector.performClick()
        popup.assertIsDisplayed()

        val items = onAllNodes(hasAnyAncestor(isPopup()) and hasRequestFocusAction())
        items.assertCountEquals(personas.size)
        personas.forEachIndexed { index, persona ->
            items[index].assertTextContains(persona.name)
            items[index].onChild().assertTextContains(persona.nickname)
        }
Ideally, testing my
GenericSelector
would be easier as I could inject test tags in my selector's items. But this is also an exercise to understand how to best test "complex" composables. Thanks in advance for your guidance.