mirror of
https://github.com/openMF/mifos-mobile.git
synced 2026-02-06 11:26:51 +00:00
200 lines
7.4 KiB
Plaintext
200 lines
7.4 KiB
Plaintext
package org.mifos.mobile.feature.${feature_lowercase}
|
|
|
|
import app.cash.turbine.test
|
|
import kotlin.test.BeforeTest
|
|
import kotlin.test.AfterTest
|
|
import kotlin.test.Test
|
|
import kotlin.test.assertEquals
|
|
import kotlin.test.assertTrue
|
|
import kotlin.test.assertNull
|
|
import kotlin.test.assertNotNull
|
|
import kotlinx.coroutines.test.runTest
|
|
import org.mifos.mobile.core.testing.fake.Fake${Feature}Repository
|
|
import org.mifos.mobile.core.testing.fixtures.${Feature}Fixtures
|
|
import org.mifos.mobile.core.testing.rule.MainDispatcherRule
|
|
|
|
class ${Feature}ViewModelTest {
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// SETUP
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
private val mainDispatcherRule = MainDispatcherRule()
|
|
|
|
private lateinit var viewModel: ${Feature}ViewModel
|
|
private lateinit var fakeRepository: Fake${Feature}Repository
|
|
|
|
@BeforeTest
|
|
fun setup() {
|
|
fakeRepository = Fake${Feature}Repository()
|
|
viewModel = ${Feature}ViewModel(
|
|
repository = fakeRepository
|
|
)
|
|
}
|
|
|
|
@AfterTest
|
|
fun teardown() {
|
|
fakeRepository.reset()
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// INITIAL STATE TESTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
@Test
|
|
fun `initial state is loading`() = runTest {
|
|
viewModel.stateFlow.test {
|
|
val state = awaitItem()
|
|
assertTrue(state.uiState is ${Feature}UiState.Loading)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `initial dialog state is null`() = runTest {
|
|
viewModel.stateFlow.test {
|
|
val state = awaitItem()
|
|
assertNull(state.dialogState)
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// SUCCESS STATE TESTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
@Test
|
|
fun `load success updates state with data`() = runTest {
|
|
// Given
|
|
val testData = ${Feature}Fixtures.createList(5)
|
|
fakeRepository.setLoadSuccess(testData)
|
|
|
|
// When
|
|
viewModel.loadData()
|
|
|
|
// Then
|
|
viewModel.stateFlow.test {
|
|
val state = expectMostRecentItem()
|
|
assertTrue(state.uiState is ${Feature}UiState.Success)
|
|
assertEquals(testData, (state.uiState as ${Feature}UiState.Success).data)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `empty data shows success with empty list`() = runTest {
|
|
// Given
|
|
fakeRepository.setLoadEmpty()
|
|
|
|
// When
|
|
viewModel.loadData()
|
|
|
|
// Then
|
|
viewModel.stateFlow.test {
|
|
val state = expectMostRecentItem()
|
|
assertTrue(state.uiState is ${Feature}UiState.Success)
|
|
assertTrue((state.uiState as ${Feature}UiState.Success).data.isEmpty())
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ERROR STATE TESTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
@Test
|
|
fun `load error shows error state`() = runTest {
|
|
// Given
|
|
fakeRepository.setLoadError("Network error")
|
|
|
|
// When
|
|
viewModel.loadData()
|
|
|
|
// Then
|
|
viewModel.stateFlow.test {
|
|
val state = expectMostRecentItem()
|
|
assertTrue(state.uiState is ${Feature}UiState.Error)
|
|
assertEquals("Network error", (state.uiState as ${Feature}UiState.Error).message)
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ACTION TESTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
@Test
|
|
fun `refresh action reloads data`() = runTest {
|
|
// Given
|
|
fakeRepository.setLoadSuccess(emptyList())
|
|
|
|
// When
|
|
viewModel.loadData()
|
|
viewModel.trySendAction(${Feature}Action.Refresh)
|
|
|
|
// Then
|
|
assertEquals(2, fakeRepository.loadCallCount)
|
|
}
|
|
|
|
@Test
|
|
fun `item click triggers navigation event`() = runTest {
|
|
// Given
|
|
val itemId = 1L
|
|
|
|
// When
|
|
viewModel.trySendAction(${Feature}Action.ItemClicked(itemId))
|
|
|
|
// Then
|
|
viewModel.eventFlow.test {
|
|
val event = awaitItem()
|
|
assertEquals(${Feature}Event.NavigateToDetail(itemId), event)
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// DIALOG TESTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
@Test
|
|
fun `delete action shows confirmation dialog`() = runTest {
|
|
// Given
|
|
val itemId = 1L
|
|
|
|
// When
|
|
viewModel.trySendAction(${Feature}Action.DeleteClicked(itemId))
|
|
|
|
// Then
|
|
viewModel.stateFlow.test {
|
|
val state = expectMostRecentItem()
|
|
assertNotNull(state.dialogState)
|
|
assertTrue(state.dialogState is DialogState.Confirmation)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `dismiss dialog clears dialog state`() = runTest {
|
|
// Given
|
|
viewModel.trySendAction(${Feature}Action.DeleteClicked(1L))
|
|
|
|
// When
|
|
viewModel.trySendAction(${Feature}Action.DismissDialog)
|
|
|
|
// Then
|
|
viewModel.stateFlow.test {
|
|
val state = expectMostRecentItem()
|
|
assertNull(state.dialogState)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `confirm delete calls repository`() = runTest {
|
|
// Given
|
|
fakeRepository.setDeleteSuccess()
|
|
|
|
// When
|
|
viewModel.trySendAction(${Feature}Action.ConfirmDelete(itemId = 1L))
|
|
|
|
// Then
|
|
assertEquals(1, fakeRepository.deleteCallCount)
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// TODO: Add more tests for specific feature logic
|
|
// ═══════════════════════════════════════════════════════════════
|
|
}
|