Ignore line breaks in single line text inputs
This commit is contained in:
parent
87947e1e77
commit
e142ba4ca3
8 changed files with 226 additions and 95 deletions
|
@ -5,6 +5,12 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import app.k9mail.core.ui.compose.theme.PreviewWithThemes
|
||||
|
||||
private val LINE_BREAK = "[\\r\\n]".toRegex()
|
||||
|
||||
internal fun stripLineBreaks(onValueChange: (String) -> Unit): (String) -> Unit = { value ->
|
||||
onValueChange(value.replace(LINE_BREAK, replacement = ""))
|
||||
}
|
||||
|
||||
internal fun selectLabel(
|
||||
label: String?,
|
||||
isRequired: Boolean,
|
||||
|
|
|
@ -26,7 +26,7 @@ fun TextFieldOutlined(
|
|||
) {
|
||||
MaterialOutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
onValueChange = if (isSingleLine) stripLineBreaks(onValueChange) else onValueChange,
|
||||
modifier = modifier,
|
||||
enabled = isEnabled,
|
||||
label = selectLabel(label, isRequired),
|
||||
|
|
|
@ -22,7 +22,7 @@ fun TextFieldOutlinedEmailAddress(
|
|||
) {
|
||||
MaterialOutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
onValueChange = stripLineBreaks(onValueChange),
|
||||
modifier = modifier,
|
||||
enabled = isEnabled,
|
||||
label = selectLabel(label, isRequired),
|
||||
|
|
|
@ -35,7 +35,7 @@ fun TextFieldOutlinedPassword(
|
|||
|
||||
MaterialOutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
onValueChange = stripLineBreaks(onValueChange),
|
||||
modifier = modifier,
|
||||
enabled = isEnabled,
|
||||
label = selectLabel(label, isRequired),
|
||||
|
@ -70,7 +70,7 @@ fun TextFieldOutlinedPassword(
|
|||
) {
|
||||
MaterialOutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
onValueChange = stripLineBreaks(onValueChange),
|
||||
modifier = modifier,
|
||||
enabled = isEnabled,
|
||||
label = selectLabel(label, isRequired),
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package app.k9mail.core.ui.compose.designsystem.atom.textfield
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import app.k9mail.core.ui.compose.testing.ComposeTest
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private const val TEST_TAG = "TextFieldOutlinedEmailAddress"
|
||||
|
||||
class TextFieldOutlinedEmailAddressKtTest : ComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `should call onValueChange when value changes`() = runComposeTest {
|
||||
var value = "initial"
|
||||
setContent {
|
||||
TextFieldOutlinedEmailAddress(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("initial + added text")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should strip line breaks before onValueChange is called`() = runComposeTest {
|
||||
var value = ""
|
||||
setContent {
|
||||
TextFieldOutlinedEmailAddress(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput("one\n two")
|
||||
|
||||
assertThat(value).isEqualTo("one two")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package app.k9mail.core.ui.compose.designsystem.atom.textfield
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import app.k9mail.core.ui.compose.testing.ComposeTest
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private const val TEST_TAG = "TextFieldOutlined"
|
||||
|
||||
class TextFieldOutlinedKtTest : ComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `should call onValueChange when value changes with isSingleLine = false`() = runComposeTest {
|
||||
var value = "initial"
|
||||
setContent {
|
||||
TextFieldOutlined(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isSingleLine = false,
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("initial + added text")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should call onValueChange when value changes with isSingleLine = true`() = runComposeTest {
|
||||
var value = "initial"
|
||||
setContent {
|
||||
TextFieldOutlined(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isSingleLine = true,
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("initial + added text")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow line breaks when isSingleLine = false`() = runComposeTest {
|
||||
var value = ""
|
||||
setContent {
|
||||
TextFieldOutlined(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isSingleLine = false,
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput("one\ntwo")
|
||||
|
||||
assertThat(value).isEqualTo("one\ntwo")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should strip line breaks before onValueChange is called when isSingleLine = true`() = runComposeTest {
|
||||
var value = ""
|
||||
setContent {
|
||||
TextFieldOutlined(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isSingleLine = true,
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput("one\n two")
|
||||
|
||||
assertThat(value).isEqualTo("one two")
|
||||
}
|
||||
}
|
|
@ -1,18 +1,24 @@
|
|||
package app.k9mail.core.ui.compose.designsystem.atom.textfield
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.test.SemanticsNodeInteraction
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import app.k9mail.core.ui.compose.designsystem.R
|
||||
import app.k9mail.core.ui.compose.testing.ComposeTest
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isTrue
|
||||
import org.junit.Test
|
||||
|
||||
private const val PASSWORD = "Password input"
|
||||
private const val TEST_TAG = "TextFieldOutlinedPassword"
|
||||
|
||||
class TextFieldOutlinedPasswordKtTest : ComposeTest() {
|
||||
|
||||
|
@ -131,6 +137,78 @@ class TextFieldOutlinedPasswordKtTest : ComposeTest() {
|
|||
onNodeWithText(PASSWORD).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `variant 1 should call onValueChange when value changes`() = runComposeTest {
|
||||
var value = "initial"
|
||||
setContent {
|
||||
TextFieldOutlinedPassword(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("initial + added text")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `variant 2 should call onValueChange when value changes`() = runComposeTest {
|
||||
var value = "initial"
|
||||
setContent {
|
||||
TextFieldOutlinedPassword(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isPasswordVisible = false,
|
||||
onPasswordVisibilityToggleClicked = {},
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("initial + added text")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `variant 1 should strip line breaks before onValueChange is called`() = runComposeTest {
|
||||
var value = ""
|
||||
setContent {
|
||||
TextFieldOutlinedPassword(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput("one\n two")
|
||||
|
||||
assertThat(value).isEqualTo("one two")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `variant 2 should strip line breaks before onValueChange is called`() = runComposeTest {
|
||||
var value = ""
|
||||
setContent {
|
||||
TextFieldOutlinedPassword(
|
||||
value = value,
|
||||
onValueChange = { value = it },
|
||||
isPasswordVisible = false,
|
||||
onPasswordVisibilityToggleClicked = {},
|
||||
modifier = Modifier.testTag(TEST_TAG),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(TEST_TAG).performClick()
|
||||
onNodeWithTag(TEST_TAG).performTextInput("one\n two")
|
||||
|
||||
assertThat(value).isEqualTo("one two")
|
||||
}
|
||||
|
||||
private fun SemanticsNodeInteractionsProvider.onShowPasswordNode(): SemanticsNodeInteraction {
|
||||
return onNodeWithContentDescription(
|
||||
getString(R.string.designsystem_atom_password_textfield_show_password),
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package app.k9mail.core.ui.compose.designsystem.atom.textfield
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import app.k9mail.core.ui.compose.testing.ComposeTest
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner
|
||||
|
||||
data class TextInputTextFieldTestData(
|
||||
val name: String,
|
||||
val input: String,
|
||||
val content: @Composable (
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier,
|
||||
) -> Unit,
|
||||
)
|
||||
|
||||
@RunWith(ParameterizedRobolectricTestRunner::class)
|
||||
class TextInputTextFieldTest(
|
||||
data: TextInputTextFieldTestData,
|
||||
) : ComposeTest() {
|
||||
|
||||
private val testSubjectName = data.name
|
||||
private val testSubject = data.content
|
||||
private val testInput = data.input
|
||||
|
||||
@Test
|
||||
fun `should call onValueChange when value changes`() = runComposeTest {
|
||||
var value = testInput
|
||||
setContent {
|
||||
testSubject(
|
||||
value,
|
||||
{ value = it },
|
||||
Modifier.testTag(testSubjectName),
|
||||
)
|
||||
}
|
||||
|
||||
onNodeWithTag(testSubjectName).performClick()
|
||||
onNodeWithTag(testSubjectName).performTextInput(" + added text")
|
||||
|
||||
assertThat(value).isEqualTo("$testInput + added text")
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
|
||||
fun data(): List<TextInputTextFieldTestData> = listOf(
|
||||
TextInputTextFieldTestData(
|
||||
name = "TextFieldOutlined",
|
||||
input = "value",
|
||||
content = { value, onValueChange: (String) -> Unit, modifier ->
|
||||
TextFieldOutlined(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
),
|
||||
TextInputTextFieldTestData(
|
||||
name = "TextFieldOutlinedPassword",
|
||||
input = "value",
|
||||
content = { value, onValueChange: (String) -> Unit, modifier ->
|
||||
TextFieldOutlinedPassword(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
),
|
||||
TextInputTextFieldTestData(
|
||||
name = "TextFieldOutlinedEmail",
|
||||
input = "value",
|
||||
content = { value, onValueChange: (String) -> Unit, modifier ->
|
||||
TextFieldOutlinedEmailAddress(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue