From 9fa87fa26e91b13a635d9e346cea1c3707080366 Mon Sep 17 00:00:00 2001 From: Xavier Molloy <44061143+xavimolloy@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:33:49 +0200 Subject: [PATCH] ANDROAPP-5500-mobile-ui-Create-Input-Long-Text (#45) * add InputLongText component, add documentation * implement tests for new component * ktlint --- .../kotlin/org/hisp/dhis/common/App.kt | 5 +- .../hisp/dhis/common/screens/Components.kt | 1 + .../common/screens/FormsComponentsScreen.kt | 2 +- .../common/screens/InputLongTextScreen.kt | 173 ++++++++++++++++++ .../ui/designsystem/component/InputField.kt | 8 +- .../designsystem/component/InputLongText.kt | 122 ++++++++++++ .../ui/designsystem/component/InputShell.kt | 3 +- .../mobile/ui/designsystem/theme/Spacing.kt | 1 + .../component/InputLongTextTest.kt | 145 +++++++++++++++ 9 files changed, 455 insertions(+), 5 deletions(-) create mode 100644 common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt create mode 100644 designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt index 76964a59c..df7cc39bf 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt @@ -30,6 +30,7 @@ import org.hisp.dhis.common.screens.FormShellsScreen import org.hisp.dhis.common.screens.FormsComponentsScreen import org.hisp.dhis.common.screens.IconButtonScreen import org.hisp.dhis.common.screens.InputIntegerScreen +import org.hisp.dhis.common.screens.InputLongTextScreen import org.hisp.dhis.common.screens.InputNegativeIntegerScreen import org.hisp.dhis.common.screens.InputNumberScreen import org.hisp.dhis.common.screens.InputPercentageScreen @@ -55,7 +56,7 @@ fun App() { @Composable fun Main() { - val currentScreen = remember { mutableStateOf(Components.INPUT_NUMBER) } + val currentScreen = remember { mutableStateOf(Components.INPUT_LONG_TEXT) } var expanded by remember { mutableStateOf(false) } Column( @@ -66,7 +67,6 @@ fun Main() { Box( modifier = Modifier .fillMaxWidth(), - ) { TextField( readOnly = true, @@ -113,6 +113,7 @@ fun Main() { Components.INPUT -> InputScreen() Components.SUPPORTING_TEXT -> SupportingTextScreen() Components.INPUT_TEXT -> InputTextScreen() + Components.INPUT_LONG_TEXT -> InputLongTextScreen() Components.LEGEND_DESCRIPTION -> LegendDescriptionScreen() Components.FORM_SHELLS -> FormShellsScreen() Components.BUTTON_BLOCK -> ButtonBlockScreen() diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt index 83c61b2b2..8784666d8 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt @@ -22,4 +22,5 @@ enum class Components(val label: String) { BOTTOM_SHEET("Bottom Sheet"), TAGS("Tags"), SECTIONS("Sections"), + INPUT_LONG_TEXT("Input Long Text"), } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormsComponentsScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormsComponentsScreen.kt index 3c5fd447f..6e7ba6fab 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormsComponentsScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormsComponentsScreen.kt @@ -12,7 +12,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle fun FormsComponentsScreen() { ColumnComponentContainer("Input Shell") { SubTitle("Sample functional Input Shell ") - InputShellPreview("Label", inputField = { BasicInput("Helper", true, InputStyle.WITH_HELPER_BEFORE, onInputChanged = {}) }) + InputShellPreview("Label", inputField = { BasicInput("Helper", true, helperStyle = InputStyle.WITH_HELPER_BEFORE, onInputChanged = {}) }) SubTitle("Unfocused Input shell ") InputShellPreview("Label") SubTitle("Focused ") diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt new file mode 100644 index 000000000..9b6d40254 --- /dev/null +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt @@ -0,0 +1,173 @@ +package org.hisp.dhis.common.screens + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.text.input.ImeAction +import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer +import org.hisp.dhis.mobile.ui.designsystem.component.InputLongText +import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState +import org.hisp.dhis.mobile.ui.designsystem.component.LegendData +import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle +import org.hisp.dhis.mobile.ui.designsystem.component.SupportingTextData +import org.hisp.dhis.mobile.ui.designsystem.component.SupportingTextState +import org.hisp.dhis.mobile.ui.designsystem.component.Title +import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor +import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor + +@Composable +fun InputLongTextScreen() { + ColumnComponentContainer { + Title("Input Long Text component", textColor = TextColor.OnSurfaceVariant) + SubTitle(" Basic Input Long Text", textColor = TextColor.OnSurfaceVariant) + var inputValue1 by rememberSaveable { + mutableStateOf( + "Lorem ipsum dolor sit amet," + + " consectetur adipiscing elit. " + + "Maecenas dolor lacus, aliquam.", + ) + } + + InputLongText( + title = "Label", + inputText = inputValue1, + onValueChanged = { + if (it != null) { + inputValue1 = it + } + }, + ) + SubTitle(" Basic Input Long Text with error message", textColor = TextColor.OnSurfaceVariant) + var inputValueError by rememberSaveable { + mutableStateOf( + "Lorem ipsum dolor sit amet," + + " consectetur adipiscing elit. " + + "Maecenas dolor lacus, aliquam." + + "Lorem ipsum dolor sit amet," + + " consectetur adipiscing elit. " + + "Maecenas dolor lacus, aliquam." + + "Lorem ipsum dolor sit amet," + + " consectetur adipiscing elit. " + + "Maecenas dolor lacus, aliquam." + + "Lorem ipsum dolor sit amet," + + " consectetur adipiscing elit. " + + "Maecenas dolor lacus, aliquam.", + ) + } + + InputLongText( + title = "Label", + inputText = inputValueError, + onValueChanged = { + if (it != null) { + inputValueError = it + } + }, + supportingText = listOf( + SupportingTextData( + "100000/1000000 characters used", + state = SupportingTextState.ERROR, + ), + ), + state = InputShellState.ERROR, + ) + + var inputValue2 by rememberSaveable { mutableStateOf("") } + SubTitle("Input long text with legend", textColor = TextColor.OnSurfaceVariant) + InputLongText( + title = "Label", + inputText = inputValue2, + legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + onValueChanged = { + if (it != null) { + inputValue2 = it + } + }, + ) + + var inputValue3 by rememberSaveable { mutableStateOf("") } + + SubTitle("Input Long text with Supporting text", textColor = TextColor.OnSurfaceVariant) + InputLongText( + title = "Label", + inputText = inputValue3, + supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + onValueChanged = { + if (it != null) { + inputValue3 = it + } + }, + ) + + var inputValue4 by rememberSaveable { mutableStateOf("") } + + SubTitle("Input Long Text with Supporting text and legend", textColor = TextColor.OnSurfaceVariant) + + InputLongText( + title = "Label", + inputText = inputValue4, + supportingText = listOf( + SupportingTextData( + "Supporting text", + SupportingTextState.DEFAULT, + ), + ), + legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + onValueChanged = { + if (it != null) { + inputValue4 = it + } + }, + ) + SubTitle("Input Long text with error and warning text and legend", textColor = TextColor.OnSurfaceVariant) + var inputValue5 by rememberSaveable { mutableStateOf("") } + + InputLongText( + title = "Label", + inputText = inputValue5, + supportingText = listOf( + SupportingTextData("Supporting text", SupportingTextState.DEFAULT), + SupportingTextData("Supporting text", SupportingTextState.WARNING), + SupportingTextData("Supporting text", SupportingTextState.ERROR), + + ), + legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.ERROR, + imeAction = ImeAction.Done, + onValueChanged = { + if (it != null) { + inputValue5 = it + } + }, + ) + var inputValue6 by rememberSaveable { mutableStateOf("") } + + SubTitle("Disabled Input Long Text ", textColor = TextColor.OnSurfaceVariant) + InputLongText( + title = "Label", + inputText = inputValue6, + state = InputShellState.DISABLED, + onValueChanged = { + if (it != null) { + inputValue6 = it + } + }, + ) + + var inputValue7 by rememberSaveable { mutableStateOf("Content") } + + SubTitle("Disabled Input text with content ", textColor = TextColor.OnSurfaceVariant) + InputLongText( + title = "Label", + inputText = inputValue7, + state = InputShellState.DISABLED, + onValueChanged = { + if (it != null) { + inputValue7 = it + } + }, + ) + } +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt index c6217b251..9d7f7354b 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt @@ -64,15 +64,21 @@ fun EmptyInput( * @param helper Manages the helper text to be shown * @param enabled Controls the enabled state of the component. When `false`, this component will not be * clickable and will appear disabled to accessibility services. + * @param isSingleLine manages the number of lines to be allowed in the input field * @param helperStyle manages the helper text style, NONE by default * @param inputText manages the value of the input field text * @param onInputChanged gives access to the onTextChangedEvent + * @param modifier to pass a modifier if necessary + * @param state manages the color of cursor depending on the state of parent component + * @param keyboardOptions manages the ImeAction to be shown on the keyboard + * @param onNextClicked gives access to the ImeAction event */ @OptIn(ExperimentalComposeUiApi::class) @Composable fun BasicInput( helper: String? = null, enabled: Boolean = true, + isSingleLine: Boolean = true, helperStyle: InputStyle = InputStyle.NONE, inputText: String = "", onInputChanged: (String) -> Unit, @@ -119,7 +125,7 @@ fun BasicInput( onValueChange = onInputChanged, enabled = enabled, textStyle = MaterialTheme.typography.bodyLarge.copy(color = if (enabled) TextColor.OnSurface else TextColor.OnDisabledSurface), - singleLine = true, + singleLine = isSingleLine, decorationBox = { innerTextField -> Row( verticalAlignment = Alignment.CenterVertically, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt new file mode 100644 index 000000000..235b7f1d1 --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt @@ -0,0 +1,122 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Cancel +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.input.ImeAction +import org.hisp.dhis.mobile.ui.designsystem.theme.InternalSizeValues +import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing + +/** + * DHIS2 Input Long Text. Wraps DHIS ยท [InputShell]. + * @param title controls the text to be shown for the title + * @param state Manages the InputShell state + * @param supportingText is a list of SupportingTextData that + * manages all the messages to be shown + * @param legendData manages the legendComponent + * @param inputText manages the value of the text in the input field + * @param isRequiredField manages whether the field is mandatory or not + * @param onNextClicked gives access to the ImeAction event + * @param onValueChanged gives access to the onValueChanged event + * @param imeAction controls the ImeAction to show in the keyboard + * @param modifier allows a modifier to be passed externally + */ +@Composable +fun InputLongText( + title: String, + state: InputShellState = InputShellState.UNFOCUSED, + supportingText: List? = null, + legendData: LegendData? = null, + inputText: String? = null, + isRequiredField: Boolean = false, + onNextClicked: (() -> Unit)? = null, + onValueChanged: ((String?) -> Unit)? = null, + imeAction: ImeAction = ImeAction.Next, + modifier: Modifier = Modifier, +) { + val inputValue by remember(inputText) { mutableStateOf(inputText ?: "") } + var deleteButtonIsVisible by remember { + mutableStateOf(!inputText.isNullOrEmpty() && state != InputShellState.DISABLED) + } + val focusManager = LocalFocusManager.current + + val keyboardOptions = KeyboardOptions(imeAction = imeAction) + InputShell( + modifier = modifier, + isRequiredField = isRequiredField, + title = title, + primaryButton = { + if (deleteButtonIsVisible) { + IconButton( + modifier = Modifier.testTag("INPUT_LONG_TEXT_RESET_BUTTON"), + icon = { + Icon( + imageVector = Icons.Outlined.Cancel, + contentDescription = "Icon Button", + ) + }, + onClick = { + onValueChanged?.invoke("") + deleteButtonIsVisible = false + }, + enabled = state != InputShellState.DISABLED, + ) + } + }, + state = state, + legend = { + legendData?.let { + Legend(legendData, Modifier.testTag("INPUT_LONG_TEXT_LEGEND")) + } + }, + supportingText = { + supportingText?.forEach { + label -> + SupportingText( + label.text, + label.state, + modifier = Modifier.testTag("INPUT_LONG_TEXT_SUPPORTING_TEXT"), + ) + } + }, + inputField = { + BasicInput( + modifier = Modifier.testTag("INPUT_LONG_TEXT_FIELD") + .scrollable( + orientation = Orientation.Vertical, + state = rememberScrollState(), + ).heightIn(Spacing.Spacing0, InternalSizeValues.Size300), + isSingleLine = false, + inputText = inputValue, + onInputChanged = { + onValueChanged?.invoke(it) + deleteButtonIsVisible = it.isNotEmpty() + }, + enabled = state != InputShellState.DISABLED, + state = state, + keyboardOptions = keyboardOptions, + onNextClicked = { + if (onNextClicked != null) { + onNextClicked.invoke() + } else { + focusManager.moveFocus(FocusDirection.Down) + } + }, + ) + }, + ) +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt index dd4db1729..a74dbb3f7 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt @@ -39,6 +39,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor * @param legend controls the optional legend composable * @param inputField controls the input field composable . * @param supportingText controls the supporting text composable + * @param isRequiredField controls whether the field is mandatory */ @Composable fun InputShell( @@ -112,7 +113,7 @@ private fun InputShellRow( ) { Row( horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Top, + verticalAlignment = Alignment.CenterVertically, modifier = modifier.fillMaxWidth() .background(backgroundColor) .padding(Spacing.Spacing16, Spacing.Spacing8, Spacing.Spacing0, Spacing.Spacing4), diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Spacing.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Spacing.kt index ee8e2c80f..b3d6ecf3d 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Spacing.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Spacing.kt @@ -36,6 +36,7 @@ internal object InternalSizeValues { val Size18: Dp = 18.dp val Size40: Dp = 40.dp val Size48: Dp = 48.dp + val Size300: Dp = 300.dp } internal object InternalFloatValues { diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt new file mode 100644 index 000000000..c34765c52 --- /dev/null +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt @@ -0,0 +1,145 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.assert +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.assertTextEquals +import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performTextInput +import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor +import org.junit.Rule +import org.junit.Test + +class InputLongTextTest { + + @get:Rule + val rule = createComposeRule() + + @Test + fun shouldDisplayInputTextCorrectly() { + rule.setContent { + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_LEGEND").assertDoesNotExist() + rule.onNodeWithTag("INPUT_LONG_TEXT_SUPPORTING_TEXT").assertDoesNotExist() + } + + @Test + fun shouldAllowUserInputWhenEnabled() { + rule.setContent { + var inputValue by rememberSaveable { mutableStateOf("") } + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + inputText = inputValue, + onValueChanged = { + if (it != null) { + inputValue = it + } + }, + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").performTextInput("Input") + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").assert(hasText("Input")) + } + + @Test + fun shouldNotAllowUserInputWhenDisabled() { + rule.setContent { + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + state = InputShellState.DISABLED, + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").assertIsNotEnabled() + } + + @Test + fun shouldShowResetButtonWhenTextFieldHasContent() { + rule.setContent { + var inputValue by rememberSaveable { mutableStateOf("") } + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + inputText = inputValue, + onValueChanged = { + if (it != null) { + inputValue = it + } + }, + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").performTextInput("Input") + rule.onNodeWithTag("INPUT_LONG_TEXT_RESET_BUTTON").assertExists() + } + + @Test + fun shouldDeleteContentWhenResetButtonIsClickedAndHideResetButton() { + rule.setContent { + var inputValue by rememberSaveable { mutableStateOf("Input") } + + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + inputText = inputValue, + onValueChanged = { + if (it != null) { + inputValue = it + } + }, + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_RESET_BUTTON").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_RESET_BUTTON").performClick() + rule.onNodeWithTag("INPUT_LONG_TEXT_FIELD").assertTextEquals("") + rule.onNodeWithTag("INPUT_LONG_TEXT_RESET_BUTTON").assertDoesNotExist() + } + + @Test + fun shouldShowLegendCorrectly() { + rule.setContent { + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + inputText = "Input", + legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_LEGEND").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_LEGEND").assertHasClickAction() + } + + @Test + fun shouldShowSupportingTextCorrectly() { + rule.setContent { + InputLongText( + title = "Label", + modifier = Modifier.testTag("INPUT_LONG_TEXT"), + inputText = "Input", + supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + ) + } + rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() + rule.onNodeWithTag("INPUT_LONG_TEXT_SUPPORTING_TEXT").assertExists() + } +}