Skip to content

Commit 9e1c392

Browse files
committed
🧪 [Tests]: Add test coverage for 16 hooks
Add comprehensive tests for: UseAutoReset, UseBoolean, UseCounter, UseCreation, UseCycleList, UseEvent, UseGetStateResetState, UseLatest, UseList, UseMap, UseMountUnmount, UsePrevious, UseTimeoutFn, UseToggle, UseUndo, UseUpdate.
1 parent f9366fe commit 9e1c392

16 files changed

Lines changed: 3552 additions & 0 deletions
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package xyz.junerver.compose.hooks.test
2+
3+
import androidx.compose.material3.Text
4+
import androidx.compose.runtime.SideEffect
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.setValue
7+
import androidx.compose.ui.test.ExperimentalTestApi
8+
import androidx.compose.ui.test.onNodeWithText
9+
import androidx.compose.ui.test.runComposeUiTest
10+
import kotlin.test.Test
11+
import kotlin.time.Duration.Companion.milliseconds
12+
import xyz.junerver.compose.hooks.useAutoReset
13+
import xyz.junerver.compose.hooks.useState
14+
15+
/*
16+
Description: useAutoReset comprehensive TDD tests
17+
Author: AI Assistant
18+
Date: 2026/1/24
19+
Email: junerver@gmail.com
20+
Version: v1.0
21+
*/
22+
23+
class UseAutoResetTest {
24+
@OptIn(ExperimentalTestApi::class)
25+
@Test
26+
fun useAutoReset_initial_value() = runComposeUiTest {
27+
setContent {
28+
val state by useAutoReset(0, 1000.milliseconds)
29+
Text("value=$state")
30+
}
31+
waitForIdle()
32+
onNodeWithText("value=0").assertExists()
33+
}
34+
35+
@OptIn(ExperimentalTestApi::class)
36+
@Test
37+
fun useAutoReset_can_be_modified() = runComposeUiTest {
38+
setContent {
39+
var fired by useState(false)
40+
var state by useAutoReset(0, 5000.milliseconds) // Long interval to avoid reset during test
41+
42+
SideEffect {
43+
if (!fired) {
44+
fired = true
45+
state = 100
46+
}
47+
}
48+
49+
Text("value=$state")
50+
}
51+
waitForIdle()
52+
onNodeWithText("value=100").assertExists()
53+
}
54+
55+
@OptIn(ExperimentalTestApi::class)
56+
@Test
57+
fun useAutoReset_with_string_initial() = runComposeUiTest {
58+
setContent {
59+
val state by useAutoReset("default", 5000.milliseconds)
60+
Text("value=$state")
61+
}
62+
waitForIdle()
63+
onNodeWithText("value=default").assertExists()
64+
}
65+
66+
@OptIn(ExperimentalTestApi::class)
67+
@Test
68+
fun useAutoReset_string_can_be_modified() = runComposeUiTest {
69+
setContent {
70+
var fired by useState(false)
71+
var state by useAutoReset("default", 5000.milliseconds)
72+
73+
SideEffect {
74+
if (!fired) {
75+
fired = true
76+
state = "modified"
77+
}
78+
}
79+
80+
Text("value=$state")
81+
}
82+
waitForIdle()
83+
onNodeWithText("value=modified").assertExists()
84+
}
85+
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
package xyz.junerver.compose.hooks.test
2+
3+
import androidx.compose.material3.Text
4+
import androidx.compose.runtime.SideEffect
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.setValue
7+
import androidx.compose.ui.test.ExperimentalTestApi
8+
import androidx.compose.ui.test.onNodeWithText
9+
import androidx.compose.ui.test.runComposeUiTest
10+
import kotlin.test.Test
11+
import kotlin.test.assertEquals
12+
import xyz.junerver.compose.hooks.useBoolean
13+
import xyz.junerver.compose.hooks.useState
14+
15+
/*
16+
Description: useBoolean comprehensive TDD tests
17+
Author: AI Assistant
18+
Date: 2026/1/24
19+
Email: junerver@gmail.com
20+
Version: v1.0
21+
*/
22+
23+
class UseBooleanTest {
24+
@OptIn(ExperimentalTestApi::class)
25+
@Test
26+
fun default_value_is_false() = runComposeUiTest {
27+
setContent {
28+
val (state) = useBoolean()
29+
Text("value=${state.value}")
30+
}
31+
waitForIdle()
32+
onNodeWithText("value=false").assertExists()
33+
}
34+
35+
@OptIn(ExperimentalTestApi::class)
36+
@Test
37+
fun default_value_can_be_set_to_true() = runComposeUiTest {
38+
setContent {
39+
val (state) = useBoolean(default = true)
40+
Text("value=${state.value}")
41+
}
42+
waitForIdle()
43+
onNodeWithText("value=true").assertExists()
44+
}
45+
46+
@OptIn(ExperimentalTestApi::class)
47+
@Test
48+
fun toggle_switches_value() = runComposeUiTest {
49+
setContent {
50+
var phase by useState(0)
51+
val (state, toggle) = useBoolean(default = false)
52+
53+
SideEffect {
54+
when (phase) {
55+
0 -> {
56+
toggle()
57+
phase = 1
58+
}
59+
}
60+
}
61+
62+
Text("value=${state.value} phase=$phase")
63+
}
64+
waitForIdle()
65+
onNodeWithText("value=true phase=1").assertExists()
66+
}
67+
68+
@OptIn(ExperimentalTestApi::class)
69+
@Test
70+
fun toggle_twice_returns_to_original() = runComposeUiTest {
71+
setContent {
72+
var phase by useState(0)
73+
val (state, toggle) = useBoolean(default = false)
74+
75+
SideEffect {
76+
when (phase) {
77+
0 -> {
78+
toggle()
79+
phase = 1
80+
}
81+
1 -> {
82+
toggle()
83+
phase = 2
84+
}
85+
}
86+
}
87+
88+
Text("value=${state.value} phase=$phase")
89+
}
90+
waitForIdle()
91+
onNodeWithText("value=false phase=2").assertExists()
92+
}
93+
94+
@OptIn(ExperimentalTestApi::class)
95+
@Test
96+
fun setTrue_sets_value_to_true() = runComposeUiTest {
97+
setContent {
98+
var fired by useState(false)
99+
val holder = useBoolean(default = false)
100+
101+
SideEffect {
102+
if (!fired) {
103+
fired = true
104+
holder.setTrue()
105+
}
106+
}
107+
108+
Text("value=${holder.state.value}")
109+
}
110+
waitForIdle()
111+
onNodeWithText("value=true").assertExists()
112+
}
113+
114+
@OptIn(ExperimentalTestApi::class)
115+
@Test
116+
fun setFalse_sets_value_to_false() = runComposeUiTest {
117+
setContent {
118+
var fired by useState(false)
119+
val holder = useBoolean(default = true)
120+
121+
SideEffect {
122+
if (!fired) {
123+
fired = true
124+
holder.setFalse()
125+
}
126+
}
127+
128+
Text("value=${holder.state.value}")
129+
}
130+
waitForIdle()
131+
onNodeWithText("value=false").assertExists()
132+
}
133+
134+
@OptIn(ExperimentalTestApi::class)
135+
@Test
136+
fun setValue_sets_specific_value() = runComposeUiTest {
137+
setContent {
138+
var phase by useState(0)
139+
val holder = useBoolean(default = false)
140+
141+
SideEffect {
142+
when (phase) {
143+
0 -> {
144+
holder.setValue(true)
145+
phase = 1
146+
}
147+
1 -> {
148+
holder.setValue(false)
149+
phase = 2
150+
}
151+
}
152+
}
153+
154+
Text("value=${holder.state.value} phase=$phase")
155+
}
156+
waitForIdle()
157+
onNodeWithText("value=false phase=2").assertExists()
158+
}
159+
160+
@OptIn(ExperimentalTestApi::class)
161+
@Test
162+
fun setTrue_when_already_true_stays_true() = runComposeUiTest {
163+
setContent {
164+
var fired by useState(false)
165+
val holder = useBoolean(default = true)
166+
167+
SideEffect {
168+
if (!fired) {
169+
fired = true
170+
holder.setTrue()
171+
}
172+
}
173+
174+
Text("value=${holder.state.value}")
175+
}
176+
waitForIdle()
177+
onNodeWithText("value=true").assertExists()
178+
}
179+
180+
@OptIn(ExperimentalTestApi::class)
181+
@Test
182+
fun setFalse_when_already_false_stays_false() = runComposeUiTest {
183+
setContent {
184+
var fired by useState(false)
185+
val holder = useBoolean(default = false)
186+
187+
SideEffect {
188+
if (!fired) {
189+
fired = true
190+
holder.setFalse()
191+
}
192+
}
193+
194+
Text("value=${holder.state.value}")
195+
}
196+
waitForIdle()
197+
onNodeWithText("value=false").assertExists()
198+
}
199+
200+
@OptIn(ExperimentalTestApi::class)
201+
@Test
202+
fun destructuring_works_correctly() = runComposeUiTest {
203+
setContent {
204+
var fired by useState(false)
205+
val (state, toggle, setValue, setTrue, setFalse) = useBoolean(default = false)
206+
207+
SideEffect {
208+
if (!fired) {
209+
fired = true
210+
// Verify all functions are accessible
211+
setTrue()
212+
}
213+
}
214+
215+
Text("value=${state.value}")
216+
}
217+
waitForIdle()
218+
onNodeWithText("value=true").assertExists()
219+
}
220+
}

0 commit comments

Comments
 (0)