Skip to content

Commit 2af2d10

Browse files
committed
test intro ViewModel
1 parent 0825638 commit 2af2d10

File tree

3 files changed

+121
-8
lines changed

3 files changed

+121
-8
lines changed

Diff for: features/finances/impl/src/main/kotlin/br/com/mob1st/features/finances/impl/domain/usecases/StartBuilderStepUseCase.kt

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ internal class StartBuilderStepUseCase(
1717
private val categorySuggestionRepository: CategorySuggestionRepository,
1818
private val categoryFactory: Category.Factory,
1919
) {
20-
2120
/**
2221
* Prefills the categories for the given [step] if it didn't have any.
2322
* @param step The step to start the builder.

Diff for: features/finances/impl/src/main/kotlin/br/com/mob1st/features/finances/impl/ui/builder/intro/BuilderIntroViewModel.kt

+10-7
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ import kotlinx.coroutines.flow.update
1919
internal class BuilderIntroViewModel private constructor(
2020
private val startBuilderStep: StartBuilderStepUseCase,
2121
private val router: BuilderRouter,
22-
private val delegate: ConsumableDelegate<BuilderIntroConsumables>,
22+
private val consumableDelegate: ConsumableDelegate<BuilderIntroConsumables>,
2323
) : ViewModel(),
2424
UiStateOutputManager<BuilderIntroUiState>,
25-
ConsumableManager<BuilderIntroConsumables> by delegate {
25+
ConsumableManager<BuilderIntroConsumables> by consumableDelegate {
2626
constructor(
2727
startBuilderStep: StartBuilderStepUseCase,
2828
router: BuilderRouter,
2929
) : this(
3030
startBuilderStep = startBuilderStep,
3131
router = router,
32-
delegate = ConsumableDelegate(BuilderIntroConsumables()),
32+
consumableDelegate = ConsumableDelegate(BuilderIntroConsumables()),
3333
)
3434

3535
private val isLoadingState = MutableStateFlow(false)
36-
private val errorHandler = delegate.errorHandler {
36+
private val errorHandler = consumableDelegate.errorHandler {
3737
handleError(it)
3838
}
3939

@@ -44,9 +44,12 @@ internal class BuilderIntroViewModel private constructor(
4444
fun start() = launchIn(errorHandler) {
4545
isLoadingState.value = true
4646
val step = BudgetBuilder.firstStep()
47-
startBuilderStep(step)
48-
isLoadingState.value = false
49-
delegate.update {
47+
try {
48+
startBuilderStep(step)
49+
} finally {
50+
isLoadingState.value = false
51+
}
52+
consumableDelegate.update {
5053
it.copy(route = router.send(step))
5154
}
5255
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package br.com.mob1st.features.finances.impl.ui.builder.intro
2+
3+
import app.cash.turbine.test
4+
import app.cash.turbine.turbineScope
5+
import br.com.mob1st.features.finances.impl.domain.entities.BudgetBuilder
6+
import br.com.mob1st.features.finances.impl.domain.usecases.StartBuilderStepUseCase
7+
import br.com.mob1st.features.finances.impl.ui.builder.navigation.BuilderRoute
8+
import br.com.mob1st.features.finances.impl.ui.builder.navigation.BuilderRouter
9+
import br.com.mob1st.features.utils.errors.CommonError
10+
import br.com.mob1st.tests.featuresutils.MainDispatcherTestExtension
11+
import io.kotest.property.Arb
12+
import io.kotest.property.arbitrary.bind
13+
import io.kotest.property.arbitrary.next
14+
import io.mockk.coEvery
15+
import io.mockk.every
16+
import io.mockk.mockk
17+
import kotlinx.coroutines.CompletableDeferred
18+
import kotlinx.coroutines.test.runTest
19+
import org.junit.jupiter.api.BeforeEach
20+
import org.junit.jupiter.api.Test
21+
import org.junit.jupiter.api.extension.ExtendWith
22+
import kotlin.test.assertEquals
23+
import kotlin.test.assertTrue
24+
25+
@ExtendWith(MainDispatcherTestExtension::class)
26+
internal class BuilderIntroViewModelTest {
27+
private lateinit var startBuilderStep: StartBuilderStepUseCase
28+
private lateinit var router: BuilderRouter
29+
30+
@BeforeEach
31+
fun setUp() {
32+
startBuilderStep = mockk(relaxed = true)
33+
router = mockk()
34+
}
35+
36+
@Test
37+
fun `WHEN get initial state THEN assert loading is false`() = runTest {
38+
val viewModel = initViewModel()
39+
turbineScope {
40+
val receiveUiState = viewModel.uiStateOutput.testIn(backgroundScope)
41+
val receiveConsumables = viewModel.consumableUiState.testIn(backgroundScope)
42+
assertEquals(
43+
BuilderIntroUiState(false),
44+
receiveUiState.awaitItem(),
45+
)
46+
assertEquals(
47+
BuilderIntroConsumables(),
48+
receiveConsumables.awaitItem(),
49+
)
50+
}
51+
}
52+
53+
@Test
54+
fun `GIVEN a long step start WHEN start THEN assert loading is displayed`() = runTest {
55+
val completedDeferred = CompletableDeferred<Unit>()
56+
coEvery { startBuilderStep(any()) } coAnswers {
57+
completedDeferred.await()
58+
}
59+
val viewModel = initViewModel()
60+
viewModel.start()
61+
viewModel.uiStateOutput.test {
62+
val state = awaitItem()
63+
assertTrue(state.isLoading)
64+
}
65+
}
66+
67+
@Test
68+
fun `GIVEN a failure to step start WHEN start THEN assert error is displayed And loading is hidden`() = runTest {
69+
coEvery { startBuilderStep(any()) } throws Exception()
70+
val viewModel = initViewModel()
71+
viewModel.start()
72+
turbineScope {
73+
val receiveUiState = viewModel.uiStateOutput.testIn(backgroundScope)
74+
val receiveConsumables = viewModel.consumableUiState.testIn(backgroundScope)
75+
assertEquals(
76+
BuilderIntroUiState(false),
77+
receiveUiState.awaitItem(),
78+
)
79+
assertEquals(
80+
BuilderIntroConsumables(error = CommonError.Unknown),
81+
receiveConsumables.awaitItem(),
82+
)
83+
}
84+
}
85+
86+
@Test
87+
fun `GIVEN a initial action WHEN start THEN assert first step is used And router send it`() = runTest {
88+
val step = BudgetBuilder.firstStep()
89+
val route = Arb.bind<BuilderRoute>().next()
90+
every { router.send(step) } returns route
91+
val viewModel = initViewModel()
92+
viewModel.start()
93+
turbineScope {
94+
val receiveUiState = viewModel.uiStateOutput.testIn(backgroundScope)
95+
val receiveConsumables = viewModel.consumableUiState.testIn(backgroundScope)
96+
assertEquals(
97+
BuilderIntroUiState(false),
98+
receiveUiState.awaitItem(),
99+
)
100+
assertEquals(
101+
BuilderIntroConsumables(route = route),
102+
receiveConsumables.awaitItem(),
103+
)
104+
}
105+
}
106+
107+
private fun initViewModel() = BuilderIntroViewModel(
108+
startBuilderStep = startBuilderStep,
109+
router = router,
110+
)
111+
}

0 commit comments

Comments
 (0)