Skip to content

Commit 8a31c0f

Browse files
committed
test: viewmodel tests
1 parent f9ccad3 commit 8a31c0f

1 file changed

Lines changed: 249 additions & 0 deletions

File tree

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package to.bitkit.ui.settings.advanced
2+
3+
import app.cash.turbine.test
4+
import kotlinx.coroutines.ExperimentalCoroutinesApi
5+
import kotlinx.coroutines.flow.flowOf
6+
import kotlinx.coroutines.test.advanceUntilIdle
7+
import org.junit.Before
8+
import org.junit.Test
9+
import org.mockito.kotlin.mock
10+
import org.mockito.kotlin.never
11+
import org.mockito.kotlin.verify
12+
import org.mockito.kotlin.whenever
13+
import to.bitkit.data.SettingsData
14+
import to.bitkit.data.SettingsStore
15+
import to.bitkit.repositories.LightningRepo
16+
import to.bitkit.test.BaseUnitTest
17+
import kotlin.test.assertEquals
18+
import kotlin.test.assertFalse
19+
import kotlin.test.assertNotNull
20+
import kotlin.test.assertNull
21+
import kotlin.test.assertTrue
22+
23+
@OptIn(ExperimentalCoroutinesApi::class)
24+
class RgsServerViewModelTest : BaseUnitTest() {
25+
private val settingsStore: SettingsStore = mock()
26+
private val lightningRepo: LightningRepo = mock()
27+
28+
private lateinit var sut: RgsServerViewModel
29+
30+
private val defaultRgsUrl = "https://rgs.blocktank.to/snapshot"
31+
32+
@Before
33+
fun setUp() {
34+
whenever(settingsStore.data).thenReturn(
35+
flowOf(SettingsData(rgsServerUrl = defaultRgsUrl))
36+
)
37+
}
38+
39+
private fun createSut(): RgsServerViewModel = RgsServerViewModel(
40+
bgDispatcher = testDispatcher,
41+
settingsStore = settingsStore,
42+
lightningRepo = lightningRepo,
43+
)
44+
45+
@Test
46+
fun `initial state loads rgsServerUrl from settings`() = test {
47+
sut = createSut()
48+
49+
sut.uiState.test {
50+
val state = awaitItem()
51+
assertEquals(defaultRgsUrl, state.connectedRgsUrl)
52+
assertEquals(defaultRgsUrl, state.rgsUrl)
53+
assertFalse(state.hasEdited)
54+
assertFalse(state.canConnect)
55+
cancelAndIgnoreRemainingEvents()
56+
}
57+
}
58+
59+
@Test
60+
fun `setRgsUrl updates url and computes canConnect`() = test {
61+
sut = createSut()
62+
advanceUntilIdle()
63+
64+
sut.setRgsUrl("https://other.server.com/snapshot")
65+
66+
val state = sut.uiState.value
67+
assertEquals("https://other.server.com/snapshot", state.rgsUrl)
68+
assertTrue(state.hasEdited)
69+
assertTrue(state.canConnect)
70+
}
71+
72+
@Test
73+
fun `setRgsUrl trims whitespace`() = test {
74+
sut = createSut()
75+
advanceUntilIdle()
76+
77+
sut.setRgsUrl(" https://other.server.com/snapshot ")
78+
79+
assertEquals("https://other.server.com/snapshot", sut.uiState.value.rgsUrl)
80+
}
81+
82+
@Test
83+
fun `canConnect is false when url matches connected url`() = test {
84+
sut = createSut()
85+
advanceUntilIdle()
86+
87+
sut.setRgsUrl(defaultRgsUrl)
88+
89+
assertFalse(sut.uiState.value.canConnect)
90+
}
91+
92+
@Test
93+
fun `canConnect is false when url is blank`() = test {
94+
sut = createSut()
95+
advanceUntilIdle()
96+
97+
sut.setRgsUrl(" ")
98+
99+
assertFalse(sut.uiState.value.canConnect)
100+
}
101+
102+
@Test
103+
fun `canConnect is false when url is invalid`() = test {
104+
sut = createSut()
105+
advanceUntilIdle()
106+
107+
sut.setRgsUrl("not-a-url")
108+
109+
assertFalse(sut.uiState.value.canConnect)
110+
}
111+
112+
@Test
113+
fun `onClickConnect does nothing for blank url`() = test {
114+
sut = createSut()
115+
advanceUntilIdle()
116+
sut.setRgsUrl("")
117+
118+
sut.onClickConnect()
119+
advanceUntilIdle()
120+
121+
verify(lightningRepo, never()).restartWithRgsServer("")
122+
assertFalse(sut.uiState.value.isLoading)
123+
}
124+
125+
@Test
126+
fun `onClickConnect does nothing for invalid url`() = test {
127+
sut = createSut()
128+
advanceUntilIdle()
129+
sut.setRgsUrl("invalid")
130+
131+
sut.onClickConnect()
132+
advanceUntilIdle()
133+
134+
assertFalse(sut.uiState.value.isLoading)
135+
}
136+
137+
@Test
138+
fun `onClickConnect success sets connectionResult success`() = test {
139+
val newUrl = "https://other.server.com/snapshot"
140+
whenever(lightningRepo.restartWithRgsServer(newUrl))
141+
.thenReturn(Result.success(Unit))
142+
sut = createSut()
143+
advanceUntilIdle()
144+
sut.setRgsUrl(newUrl)
145+
146+
sut.onClickConnect()
147+
advanceUntilIdle()
148+
149+
val state = sut.uiState.value
150+
assertFalse(state.isLoading)
151+
val result = assertNotNull(state.connectionResult)
152+
assertTrue(result.isSuccess)
153+
}
154+
155+
@Test
156+
fun `onClickConnect failure sets connectionResult failure`() = test {
157+
val newUrl = "https://other.server.com/snapshot"
158+
val error = Exception("Connection failed")
159+
whenever(lightningRepo.restartWithRgsServer(newUrl))
160+
.thenReturn(Result.failure(error))
161+
sut = createSut()
162+
advanceUntilIdle()
163+
sut.setRgsUrl(newUrl)
164+
165+
sut.onClickConnect()
166+
advanceUntilIdle()
167+
168+
val state = sut.uiState.value
169+
assertFalse(state.isLoading)
170+
val result = assertNotNull(state.connectionResult)
171+
assertTrue(result.isFailure)
172+
assertEquals("Connection failed", result.exceptionOrNull()?.message)
173+
}
174+
175+
@Test
176+
fun `onClickConnect with invalid host sets connectionResult failure`() = test {
177+
val newUrl = "https://rapidsync.lightningdevkit/snapshot"
178+
whenever(lightningRepo.restartWithRgsServer(newUrl))
179+
.thenReturn(Result.failure(Exception("Failed to start node")))
180+
sut = createSut()
181+
advanceUntilIdle()
182+
sut.setRgsUrl(newUrl)
183+
184+
sut.onClickConnect()
185+
advanceUntilIdle()
186+
187+
val state = sut.uiState.value
188+
assertFalse(state.isLoading)
189+
val result = assertNotNull(state.connectionResult)
190+
assertTrue(result.isFailure)
191+
assertEquals("Failed to start node", result.exceptionOrNull()?.message)
192+
}
193+
194+
@Test
195+
fun `clearConnectionResult resets connectionResult to null`() = test {
196+
val newUrl = "https://other.server.com/snapshot"
197+
whenever(lightningRepo.restartWithRgsServer(newUrl))
198+
.thenReturn(Result.success(Unit))
199+
sut = createSut()
200+
advanceUntilIdle()
201+
sut.setRgsUrl(newUrl)
202+
sut.onClickConnect()
203+
advanceUntilIdle()
204+
205+
sut.clearConnectionResult()
206+
207+
assertNull(sut.uiState.value.connectionResult)
208+
}
209+
210+
@Test
211+
fun `onScan delegates to setRgsUrl`() = test {
212+
sut = createSut()
213+
advanceUntilIdle()
214+
215+
sut.onScan("https://scanned.server.com/snapshot")
216+
217+
assertEquals("https://scanned.server.com/snapshot", sut.uiState.value.rgsUrl)
218+
}
219+
220+
@Test
221+
fun `resetToDefault sets url to env default`() = test {
222+
sut = createSut()
223+
advanceUntilIdle()
224+
sut.setRgsUrl("https://custom.server.com/snapshot")
225+
226+
sut.resetToDefault()
227+
228+
val state = sut.uiState.value
229+
assertFalse(state.canReset)
230+
}
231+
232+
@Test
233+
fun `isLoading is true while connecting`() = test {
234+
val newUrl = "https://other.server.com/snapshot"
235+
whenever(lightningRepo.restartWithRgsServer(newUrl))
236+
.thenReturn(Result.success(Unit))
237+
sut = createSut()
238+
advanceUntilIdle()
239+
sut.setRgsUrl(newUrl)
240+
241+
sut.uiState.test {
242+
skipItems(1)
243+
sut.onClickConnect()
244+
val loadingState = awaitItem()
245+
assertTrue(loadingState.isLoading)
246+
cancelAndIgnoreRemainingEvents()
247+
}
248+
}
249+
}

0 commit comments

Comments
 (0)