@@ -15,7 +15,6 @@ import androidx.compose.ui.test.performClick
1515import androidx.compose.ui.test.performTextClearance
1616import androidx.compose.ui.test.performTextInput
1717import androidx.compose.ui.test.runComposeUiTest
18- import dev.robercoding.decimal.formatter.compose.formatter.UiDecimalFormatter
1918import dev.robercoding.decimal.formatter.core.formatter.DecimalFormatter
2019import dev.robercoding.decimal.formatter.core.formatter.DecimalFormatterConfiguration
2120import kotlin.test.Test
@@ -28,15 +27,12 @@ class DecimalTextFieldTest {
2827 @OptIn(ExperimentalTestApi ::class )
2928 @Test
3029 fun userSeesCorrectFullDisplayAndDeveloperGetsExpectedDataUs () = runComposeUiTest {
31- val decimalFormatter = UiDecimalFormatter (
32- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .us()),
33- prefix = " $"
34- )
30+ val decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .usd())
3531 var currentValue by mutableStateOf(decimalFormatter.format(" " ))
3632
3733 setContent {
3834 OutlinedDecimalTextField (
39- decimalValue = currentValue,
35+ value = currentValue,
4036 onValueChange = { currentValue = it },
4137 decimalFormatter = decimalFormatter,
4238 modifier = Modifier .testTag(" decimal_field" )
@@ -54,22 +50,19 @@ class DecimalTextFieldTest {
5450
5551 // ✅ Developer gets structured data
5652 assertEquals(" 2999" , currentValue.rawDigits)
57- assertEquals(" 29.99" , currentValue.display )
58- assertEquals(" $29.99" , currentValue.fullDisplay )
53+ assertEquals(" 29.99" , currentValue.parseableValue )
54+ assertEquals(" $29.99" , currentValue.displayValue )
5955 }
6056
6157 @OptIn(ExperimentalTestApi ::class )
6258 @Test
6359 fun userSeesCorrectFullDisplayAndDeveloperGetsExpectedDataEuropean () = runComposeUiTest {
64- val decimalFormatter = UiDecimalFormatter (
65- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .european()),
66- prefix = " €"
67- )
60+ val decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .euro())
6861 var currentValue by mutableStateOf(decimalFormatter.format(" " ))
6962
7063 setContent {
7164 OutlinedDecimalTextField (
72- decimalValue = currentValue,
65+ value = currentValue,
7366 onValueChange = { currentValue = it },
7467 decimalFormatter = decimalFormatter,
7568 modifier = Modifier .testTag(" decimal_field" )
@@ -83,12 +76,12 @@ class DecimalTextFieldTest {
8376 }
8477
8578 // ✅ User sees prefix in display
86- onNodeWithTag(" decimal_field" ).assertTextEquals(" € 29,99" )
79+ onNodeWithTag(" decimal_field" ).assertTextEquals(" 29,99 € " )
8780
8881 // ✅ Developer gets structured data
8982 assertEquals(" 2999" , currentValue.rawDigits)
90- assertEquals(" 29, 99" , currentValue.display )
91- assertEquals(" € 29,99" , currentValue.fullDisplay )
83+ assertEquals(" 29. 99" , currentValue.parseableValue )
84+ assertEquals(" 29,99 € " , currentValue.displayValue )
9285 }
9386
9487 // ===== 2. DIFFERENT DECIMAL FORMATTER CONFIGURATIONS =====
@@ -98,21 +91,15 @@ class DecimalTextFieldTest {
9891 fun userSeesCorrectFormattingForDifferentDecimalFormatterConfigurationOnSwitch () = runComposeUiTest {
9992 var isEuropean by mutableStateOf(false )
10093
101- val usFormatter = UiDecimalFormatter (
102- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .us()),
103- prefix = null
104- )
105- val europeanFormatter = UiDecimalFormatter (
106- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .european()),
107- prefix = null
108- )
94+ val usFormatter = DecimalFormatter (DecimalFormatterConfiguration .us())
95+ val europeanFormatter = DecimalFormatter (DecimalFormatterConfiguration .european())
10996
11097 var currentValue by mutableStateOf(usFormatter.format(" 123456" ))
11198
11299 setContent {
113100 Column {
114101 OutlinedDecimalTextField (
115- decimalValue = currentValue,
102+ value = currentValue,
116103 onValueChange = { currentValue = it },
117104 decimalFormatter = if (isEuropean) europeanFormatter else usFormatter,
118105 modifier = Modifier .testTag(" decimal_field" )
@@ -134,7 +121,9 @@ class DecimalTextFieldTest {
134121
135122 // User sees initial US format
136123 onNodeWithTag(" decimal_field" ).assertTextEquals(" 1,234.56" )
137- assertEquals(" 1,234.56" , currentValue.display)
124+ assertEquals(" 1,234.56" , currentValue.displayValue)
125+ assertEquals(" 1234.56" , currentValue.parseableValue) // Format changed
126+ assertEquals(" 123456" , currentValue.rawDigits) // Raw data unchanged
138127
139128 // User switches to European format
140129 onNodeWithTag(" switch_locale" ).performClick()
@@ -143,84 +132,82 @@ class DecimalTextFieldTest {
143132 // Same raw data, different formatting
144133 onNodeWithTag(" decimal_field" ).assertTextEquals(" 1.234,56" ) // European format
145134 assertEquals(" 123456" , currentValue.rawDigits) // Raw data unchanged
146- assertEquals(" 1.234,56" , currentValue.display) // Format changed
135+ assertEquals(" 1234.56" , currentValue.parseableValue) // Format changed
136+ assertEquals(" 1.234,56" , currentValue.displayValue) // Format changed
147137 }
148138
149139 // ===== 3. PROGRESSIVE INPUT (User typing experience) =====
150140
151141 @OptIn(ExperimentalTestApi ::class )
152142 @Test
153143 fun userSeesProgressiveFormattingWhileTyping () = runComposeUiTest {
154- val decimalFormatter = UiDecimalFormatter (
155- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .us()),
156- prefix = null
157- )
158- var currentValue by mutableStateOf(decimalFormatter.format(" " ))
144+ val usFormatter = DecimalFormatter (DecimalFormatterConfiguration .us())
145+ var currentValue by mutableStateOf(usFormatter.format(" " ))
159146
160147 setContent {
161148 OutlinedDecimalTextField (
162- decimalValue = currentValue,
149+ value = currentValue,
163150 onValueChange = { currentValue = it },
164- decimalFormatter = decimalFormatter ,
151+ decimalFormatter = usFormatter ,
165152 modifier = Modifier .testTag(" decimal_field" )
166153 )
167154 }
168155
156+ // Triple(input, expectedParseableValue, expectedDisplayValue)
169157 val testCases = listOf (
170- " 1" to " 0.01" ,
171- " 12" to " 0.12" ,
172- " 123" to " 1.23" ,
173- " 1234" to " 12.34" ,
174- " 12345" to " 123.45" ,
175- " 123456" to " 1,234.56"
158+ Triple ( " 1" , " 0.01 " , " 0.01" ) ,
159+ Triple ( " 12" , " 0.12 " , " 0.12" ) ,
160+ Triple ( " 123" , " 1.23 " , " 1.23" ) ,
161+ Triple ( " 1234" , " 12.34 " , " 12.34" ) ,
162+ Triple ( " 12345" , " 123.45 " , " 123.45" ) ,
163+ Triple ( " 123456" , " 1234.56 " , " 1,234.56" )
176164 )
177165
178- testCases.forEach { (input, expectedDisplay) ->
166+ testCases.forEach { (input, expectedParseable, expectedDisplay) ->
179167 onNodeWithTag(" decimal_field" ).performTextClearance()
180168 onNodeWithTag(" decimal_field" ).performTextInput(input)
181169
182170 waitUntil(timeoutMillis = 5000 ) {
183171 currentValue.rawDigits == input
184172 }
185173
186- // User sees progressive formatting
174+ // User sees progressive formatting in the UI
187175 onNodeWithTag(" decimal_field" ).assertTextEquals(expectedDisplay)
188176
189- // Developer gets consistent raw data
190- assertEquals(input, currentValue.rawDigits)
191- assertEquals(expectedDisplay, currentValue.display)
177+ // Developer gets consistent data from the FormattedDecimal object
178+ assertEquals(input, currentValue.rawDigits, " Raw digits should match input for: $input " )
179+ assertEquals(expectedParseable, currentValue.parseableValue, " Parseable value should be correct for input: $input " )
180+ assertEquals(expectedDisplay, currentValue.displayValue, " Display value should be correct for input: $input " )
192181 }
193182 }
194183
184+
195185 // ===== 4. STATE SYNCHRONIZATION =====
196186
197187 @OptIn(ExperimentalTestApi ::class )
198188 @Test
199189 fun componentSyncsStateChanges () = runComposeUiTest {
200- val decimalFormatter = UiDecimalFormatter (
201- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .us()),
202- prefix = null
203- )
204- var currentValue by mutableStateOf(decimalFormatter.format(" 123" ))
190+ val usFormatter = DecimalFormatter (DecimalFormatterConfiguration .us())
191+ var currentValue by mutableStateOf(usFormatter.format(" 123" ))
205192
206193 setContent {
207194 Column {
208195 OutlinedDecimalTextField (
209- decimalValue = currentValue,
196+ value = currentValue,
210197 onValueChange = { currentValue = it },
211- decimalFormatter = decimalFormatter ,
198+ decimalFormatter = usFormatter ,
212199 modifier = Modifier .testTag(" decimal_field" )
213200 )
214201
215202 Button (
216- onClick = { currentValue = decimalFormatter .format(" 56789" ) },
203+ onClick = { currentValue = usFormatter .format(" 56789" ) },
217204 modifier = Modifier .testTag(" update_button" )
218205 ) {
219206 Text (" Update Value" )
220207 }
221208
222209 Button (
223- onClick = { currentValue = decimalFormatter .format(" " ) },
210+ onClick = { currentValue = usFormatter .format(" " ) },
224211 modifier = Modifier .testTag(" clear_button" )
225212 ) {
226213 Text (" Clear" )
@@ -255,32 +242,32 @@ class DecimalTextFieldTest {
255242
256243 @OptIn(ExperimentalTestApi ::class )
257244 @Test
258- fun componentHandlesInvalidInputGracefully () = runComposeUiTest {
259- val decimalFormatter = UiDecimalFormatter (
260- decimalFormatter = DecimalFormatter (DecimalFormatterConfiguration .us()),
261- prefix = null
262- )
263- var currentValue by mutableStateOf(decimalFormatter.format(" " ))
245+ fun componentHandlesInvalidInputGracefullySimple () = runComposeUiTest {
246+ val usFormatter = DecimalFormatter (DecimalFormatterConfiguration .us())
247+ var currentValue by mutableStateOf(usFormatter.format(" " ))
264248
265249 setContent {
266250 OutlinedDecimalTextField (
267- decimalValue = currentValue,
251+ value = currentValue,
268252 onValueChange = { currentValue = it },
269- decimalFormatter = decimalFormatter ,
253+ decimalFormatter = usFormatter ,
270254 modifier = Modifier .testTag(" decimal_field" )
271255 )
272256 }
273257
274258 val testCases = listOf (
275- " abc123def" to (" 123" to " 1.23" ), // Letters filtered out
276- " ..1234.." to (" 1234" to " 12.34" ), // Special chars filtered
277- " 000123" to (" 123" to " 1.23" ), // Leading zeros removed
278- " " to (" " to " 0.00" ) // Empty input
259+ " abc123def" to Triple (" 123" , " 1.23" , " 1.23" ), // Letters filtered out
260+ " ..1234.." to Triple (" 1234" , " 12.34" , " 12.34" ), // Special chars filtered
261+ " 000123" to Triple (" 123" , " 1.23" , " 1.23" ), // Leading zeros removed
262+ " " to Triple (" " , " 0.00" , " 0.00" ), // Empty input
263+ " $#@!" to Triple (" " , " 0.00" , " 0.00" ), // No digits
264+ " 1a2b3c4d5e6f" to Triple (" 123456" , " 1234.56" , " 1,234.56" ) // Mixed with thousand separator
279265 )
280266
281267 testCases.forEach { (input, expected) ->
282268 val expectedRawDigits = expected.first
283- val expectedDisplay = expected.second
269+ val expectedParseable = expected.second
270+ val expectedDisplay = expected.third
284271
285272 onNodeWithTag(" decimal_field" ).performTextClearance()
286273 onNodeWithTag(" decimal_field" ).performTextInput(input)
@@ -289,12 +276,11 @@ class DecimalTextFieldTest {
289276 currentValue.rawDigits == expectedRawDigits
290277 }
291278
292- // User sees clean formatted output
293279 onNodeWithTag(" decimal_field" ).assertTextEquals(expectedDisplay)
294280
295- // Developer gets cleaned raw data
296281 assertEquals(expectedRawDigits, currentValue.rawDigits)
297- assertEquals(expectedDisplay, currentValue.display)
282+ assertEquals(expectedParseable, currentValue.parseableValue)
283+ assertEquals(expectedDisplay, currentValue.displayValue)
298284 }
299285 }
300286}
0 commit comments