@@ -6,9 +6,11 @@ import androidx.compose.runtime.setValue
66import androidx.compose.ui.test.ExperimentalTestApi
77import androidx.compose.ui.test.onNodeWithText
88import androidx.compose.ui.test.runComposeUiTest
9+ import kotlin.test.AfterTest
910import kotlin.test.Test
1011import kotlin.test.assertTrue
1112import kotlin.time.Clock
13+ import kotlin.time.Instant
1214import kotlin.time.Duration.Companion.milliseconds
1315import kotlin.time.Duration.Companion.seconds
1416import xyz.junerver.compose.hooks.useCountdown
@@ -24,7 +26,19 @@ import xyz.junerver.compose.hooks.utils.instantProvider
2426*/
2527
2628class UseCountdownTest {
29+ private var currentInstant: Instant = Clock .System .now()
30+
2731 private fun resetInstantProvider () {
32+ currentInstant = Clock .System .now()
33+ instantProvider = { currentInstant }
34+ }
35+
36+ private fun advanceInstant (duration : kotlin.time.Duration ) {
37+ currentInstant + = duration
38+ }
39+
40+ @AfterTest
41+ fun tearDown () {
2842 instantProvider = { Clock .System .now() }
2943 }
3044
@@ -40,8 +54,8 @@ class UseCountdownTest {
4054 @Test
4155 fun countdown_with_leftTime_counts_down () = runComposeUiTest {
4256 resetInstantProvider()
43- val baseInstant = Clock . System .now()
44- instantProvider = { baseInstant }
57+ val baseInstant = currentInstant
58+ advanceInstant( 0 .milliseconds)
4559 setContent {
4660 val countdown = useCountdown {
4761 leftTime = 500 .milliseconds
@@ -51,7 +65,7 @@ class UseCountdownTest {
5165 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} " )
5266 }
5367
54- instantProvider = { baseInstant + 250 .milliseconds }
68+ advanceInstant( 250 .milliseconds)
5569 val found = waitForCondition {
5670 waitForIdle()
5771 listOf (200 , 250 , 300 ).any { ms ->
@@ -65,8 +79,8 @@ class UseCountdownTest {
6579 @Test
6680 fun countdown_with_targetDate_counts_down () = runComposeUiTest {
6781 resetInstantProvider()
68- val baseInstant = Clock . System .now()
69- instantProvider = { baseInstant }
82+ val baseInstant = currentInstant
83+ advanceInstant( 0 .milliseconds)
7084 setContent {
7185 val countdown = useCountdown {
7286 targetDate = baseInstant + 500 .milliseconds
@@ -76,7 +90,7 @@ class UseCountdownTest {
7690 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} " )
7791 }
7892
79- instantProvider = { baseInstant + 250 .milliseconds }
93+ advanceInstant( 250 .milliseconds)
8094 val found = waitForCondition {
8195 waitForIdle()
8296 listOf (200 , 250 , 300 ).any { ms ->
@@ -90,8 +104,8 @@ class UseCountdownTest {
90104 @Test
91105 fun countdown_reaches_zero_and_stops () = runComposeUiTest {
92106 resetInstantProvider()
93- val baseInstant = Clock . System .now()
94- instantProvider = { baseInstant }
107+ val baseInstant = currentInstant
108+ advanceInstant( 0 .milliseconds)
95109 setContent {
96110 val countdown = useCountdown {
97111 leftTime = 300 .milliseconds
@@ -101,14 +115,14 @@ class UseCountdownTest {
101115 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} " )
102116 }
103117
104- instantProvider = { baseInstant + 500 .milliseconds }
118+ advanceInstant( 500 .milliseconds)
105119 val reachedZero = waitForCondition {
106120 waitForIdle()
107121 runCatching { onNodeWithText(" left=0" ).assertExists() }.isSuccess
108122 }
109123 assertTrue(reachedZero, " Expected countdown reaches zero" )
110124
111- instantProvider = { baseInstant + 900 .milliseconds }
125+ advanceInstant( 900 .milliseconds)
112126 val staysZero = waitForCondition {
113127 waitForIdle()
114128 runCatching { onNodeWithText(" left=0" ).assertExists() }.isSuccess
@@ -120,8 +134,8 @@ class UseCountdownTest {
120134 @Test
121135 fun onEnd_callback_fires_when_countdown_finishes () = runComposeUiTest {
122136 resetInstantProvider()
123- val baseInstant = Clock . System .now()
124- instantProvider = { baseInstant }
137+ val baseInstant = currentInstant
138+ advanceInstant( 0 .milliseconds)
125139 setContent {
126140 var endFired by useState(default = false )
127141 val countdown = useCountdown {
@@ -135,7 +149,7 @@ class UseCountdownTest {
135149 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} ended=$endFired " )
136150 }
137151
138- instantProvider = { baseInstant + 500 .milliseconds }
152+ advanceInstant( 500 .milliseconds)
139153 val found = waitForCondition {
140154 waitForIdle()
141155 runCatching { onNodeWithText(" left=0 ended=true" ).assertExists() }.isSuccess
@@ -189,8 +203,8 @@ class UseCountdownTest {
189203 @Test
190204 fun leftTime_takes_priority_over_targetDate () = runComposeUiTest {
191205 resetInstantProvider()
192- val baseInstant = Clock . System .now()
193- instantProvider = { baseInstant }
206+ val baseInstant = currentInstant
207+ advanceInstant( 0 .milliseconds)
194208 setContent {
195209 val countdown = useCountdown {
196210 leftTime = 500 .milliseconds
@@ -201,7 +215,7 @@ class UseCountdownTest {
201215 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} " )
202216 }
203217
204- instantProvider = { baseInstant + 250 .milliseconds }
218+ advanceInstant( 250 .milliseconds)
205219 val found = waitForCondition {
206220 waitForIdle()
207221 listOf (200 , 250 , 300 ).any { ms ->
@@ -215,8 +229,8 @@ class UseCountdownTest {
215229 @Test
216230 fun countdown_with_past_targetDate_starts_at_zero () = runComposeUiTest {
217231 resetInstantProvider()
218- val baseInstant = Clock . System .now()
219- instantProvider = { baseInstant }
232+ val baseInstant = currentInstant
233+ advanceInstant( 0 .milliseconds)
220234 setContent {
221235 val countdown = useCountdown {
222236 targetDate = baseInstant - 1 .seconds
@@ -237,8 +251,8 @@ class UseCountdownTest {
237251 @Test
238252 fun interval_change_restarts_countdown () = runComposeUiTest {
239253 resetInstantProvider()
240- val baseInstant = Clock . System .now()
241- instantProvider = { baseInstant }
254+ val baseInstant = currentInstant
255+ advanceInstant( 0 .milliseconds)
242256 setContent {
243257 var intervalMs by useState(default = 100 )
244258 val countdown = useCountdown {
@@ -249,7 +263,7 @@ class UseCountdownTest {
249263 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} interval=$intervalMs " )
250264 }
251265
252- instantProvider = { baseInstant + 250 .milliseconds }
266+ advanceInstant( 250 .milliseconds)
253267 val found = waitForCondition {
254268 waitForIdle()
255269 listOf (200 , 250 , 300 ).any { ms ->
@@ -263,8 +277,8 @@ class UseCountdownTest {
263277 @Test
264278 fun targetDate_change_resumes_countdown () = runComposeUiTest {
265279 resetInstantProvider()
266- val baseInstant = Clock . System .now()
267- instantProvider = { baseInstant }
280+ val baseInstant = currentInstant
281+ advanceInstant( 0 .milliseconds)
268282 setContent {
269283 var target by useState(default = baseInstant + 300 .milliseconds)
270284 val countdown = useCountdown {
@@ -275,7 +289,7 @@ class UseCountdownTest {
275289 Text (" left=${countdown.timeLeft.value.inWholeMilliseconds} " )
276290 }
277291
278- instantProvider = { baseInstant + 400 .milliseconds }
292+ advanceInstant( 400 .milliseconds)
279293 val found = waitForCondition {
280294 waitForIdle()
281295 runCatching { onNodeWithText(" left=0" ).assertExists() }.isSuccess
@@ -287,8 +301,8 @@ class UseCountdownTest {
287301 @Test
288302 fun formatRes_updates_reactively () = runComposeUiTest {
289303 resetInstantProvider()
290- val baseInstant = Clock . System .now()
291- instantProvider = { baseInstant }
304+ val baseInstant = currentInstant
305+ advanceInstant( 0 .milliseconds)
292306 setContent {
293307 val countdown = useCountdown {
294308 leftTime = 2 .seconds
@@ -305,12 +319,12 @@ class UseCountdownTest {
305319 }
306320 assertTrue(initialFound, " Expected initial seconds=2" )
307321
308- instantProvider = { baseInstant + 1100 .milliseconds }
322+ advanceInstant( 1100 .milliseconds)
309323 val updatedFound = waitForCondition {
310324 waitForIdle()
311325 runCatching { onNodeWithText(" seconds=1" ).assertExists() }.isSuccess ||
312326 runCatching { onNodeWithText(" seconds=0" ).assertExists() }.isSuccess
313327 }
314328 assertTrue(updatedFound, " Expected seconds to update" )
315329 }
316- }
330+ }
0 commit comments