In Unit Compose UI test, OutlinedTextField exists but is not displayed

599 Views Asked by At

I have an OutlinedTextField that I'm testing in unit tests. When I run the app, the TextField is always displayed. However, when I run the unit tests, the element exists, but is not displayed. I can't do text input without calling focus on the item, which I am assuming means the item is displayed.

Here is my OutlinedTextField:

@Composable
fun ChangeUserNameInput(
    userName: String,
    onChangeUserName: (String) -> Unit) {
    Box(modifier = Modifier.testTag(UpdateUserNameTags.USERNAME).alpha(1f)) {
        OutlinedTextField(
            modifier = Modifier
                .fillMaxWidth()
                .alpha(1f)
                .semantics { contentDescription = UpdateUserNameTags.USERNAME },
            value = userName,
            onValueChange = onChangeUserName,
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = Color.Transparent,
                focusedIndicatorColor = MaterialTheme.colors.primary,
                unfocusedIndicatorColor = niro,
                disabledIndicatorColor = Color.Transparent,
                focusedLabelColor = MaterialTheme.colors.primary,
                unfocusedLabelColor = niro,
                textColor = MaterialTheme.colors.onBackground
            ),
            label = {
                Text(text = stringResource(id = R.string.update_user_name))
            },
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Text
            )
        )
    }
}

Here is my test:

@Test
fun `test to see if username typed text is Displayed`() = runTest {
    val value = composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME)
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).assertExists()
    composeTestRule.awaitIdle()


   composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).assertIsDisplayed() ---> FAILS here
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).performTextInput(" Welsh")
    value.assertTextEquals("Kristy Welsh")

    //composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).assertTextContains("Kristy Welsh")
}

I can't figure out why the item is not displaying.

2

There are 2 best solutions below

0
Kristy Welsh On BEST ANSWER

My problem actually was that the screen was too large and a bunch of the content was off screen.

I solved it by making the screen scrollable and the doing performScrollTo:

@Test
fun `test to see if username is showing`() = runTest {
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).assertExists()
    composeTestRule.onNodeWithTag("Annotated String").assertIsDisplayed()
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).performScrollTo()
    composeTestRule.onNodeWithTag(UPDATE_USER_SCREEN).assertIsDisplayed()
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).assertTextContains("Kristy")
}
1
ceviche On

I've tested this out and got it working by setting the content at the start of your test function.

composeTestRule.setContent { ChangeUserNameInput("Kristy",{})}

It looks like you're testing the state passed to the text box is updated when you enter text - this means your set content function will need to include the composable that is holding the state of username passed to ChangeUserNameInput().

Here is the test class I used.

@RunWith(AndroidJUnit4::class) class StackTest {

@get:Rule
val composeTestRule = createComposeRule()


@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun teststack() = runTest {
    composeTestRule.setContent {  ChangeUserNameInput("Kristy",{})}
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).assertExists()
    composeTestRule.awaitIdle()
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).assertIsDisplayed() // fails here
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).performTextInput(" Welsh")
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).printToLog("OutlineTextBox Test")
    composeTestRule.onNodeWithTag(UpdateUserNameTags.USERNAME).onChildAt(0).assertTextEquals(R.string.update_user_name, "Kristy Welsh")
}

}

Final note, assertTextEquals() tests the label + value in your OutlinedTextField so you need to add the label text to your assertTextEquals() as i've done in this function.