git.iko.soy/parseable-android
on master help sign in
127 lines 4.2 kB history raw
1package com.parseable.android
3import com.parseable.android.data.model.Alert
4import com.parseable.android.data.model.ApiResult
5import com.parseable.android.data.repository.ParseableRepository
6import com.parseable.android.ui.screens.alerts.AlertsViewModel
7import io.mockk.*
8import kotlinx.coroutines.Dispatchers
9import kotlinx.coroutines.ExperimentalCoroutinesApi
10import kotlinx.coroutines.test.*
11import org.junit.After
12import org.junit.Assert.*
13import org.junit.Before
14import org.junit.Test
16@OptIn(ExperimentalCoroutinesApi::class)
17class AlertsViewModelTest {
19 private lateinit var repository: ParseableRepository
20 private lateinit var viewModel: AlertsViewModel
21 private val testDispatcher = UnconfinedTestDispatcher()
23 @Before
24 fun setup() {
25 Dispatchers.setMain(testDispatcher)
26 repository = mockk(relaxed = true)
27 // The ViewModel loads once in init { refresh() }. Give that load a deterministic
28 // empty-success default so the initial state is clean; tests that exercise refresh
29 // override this stub and call refresh() again.
30 coEvery { repository.listAlerts() } returns ApiResult.Success(emptyList())
31 viewModel = AlertsViewModel(repository)
32 }
34 @After
35 fun tearDown() {
36 Dispatchers.resetMain()
37 }
39 @Test
40 fun `initial state has empty alerts and no loading`() {
41 val state = viewModel.state.value
42 assertTrue(state.alerts.isEmpty())
43 assertFalse(state.isLoading)
44 assertNull(state.error)
45 assertNull(state.alertToDelete)
46 }
48 @Test
49 fun `refresh loads alerts on success`() = runTest {
50 val alerts = listOf(
51 Alert(id = "1", title = "Alert 1", datasets = listOf("stream1"), state = "NotTriggered"),
52 Alert(id = "2", title = "Alert 2", datasets = listOf("stream2"), state = "Triggered"),
53 )
54 coEvery { repository.listAlerts() } returns ApiResult.Success(alerts)
56 viewModel.refresh()
58 val state = viewModel.state.value
59 assertEquals(alerts, state.alerts)
60 assertFalse(state.isLoading)
61 assertNull(state.error)
62 }
64 @Test
65 fun `refresh shows error on failure`() = runTest {
66 coEvery { repository.listAlerts() } returns ApiResult.Error("Server error", 500)
68 viewModel.refresh()
70 val state = viewModel.state.value
71 assertTrue(state.alerts.isEmpty())
72 assertFalse(state.isLoading)
73 assertNotNull(state.error)
74 }
76 @Test
77 fun `requestDelete sets alertToDelete`() {
78 val alert = Alert(id = "1", title = "Alert 1", datasets = listOf("stream1"))
80 viewModel.requestDelete(alert)
82 val state = viewModel.state.value
83 assertEquals(alert, state.alertToDelete)
84 }
86 @Test
87 fun `cancelDelete clears alertToDelete`() {
88 val alert = Alert(id = "1", title = "Alert 1", datasets = listOf("stream1"))
89 viewModel.requestDelete(alert)
90 assertEquals(alert, viewModel.state.value.alertToDelete)
92 viewModel.cancelDelete()
94 assertNull(viewModel.state.value.alertToDelete)
95 }
97 @Test
98 fun `deleteAlert on success refreshes list`() = runTest {
99 val alerts = listOf(
100 Alert(id = "2", title = "Alert 2", datasets = listOf("stream2")),
101 )
102 coEvery { repository.deleteAlert("1") } returns ApiResult.Success("deleted")
103 coEvery { repository.listAlerts() } returns ApiResult.Success(alerts)
105 viewModel.deleteAlert("1")
107 val state = viewModel.state.value
108 assertEquals(alerts, state.alerts)
109 assertFalse(state.isLoading)
110 assertNull(state.error)
111 assertNull(state.alertToDelete)
112 coVerify { repository.deleteAlert("1") }
113 coVerify { repository.listAlerts() }
114 }
116 @Test
117 fun `deleteAlert on error shows error message`() = runTest {
118 coEvery { repository.deleteAlert("1") } returns ApiResult.Error("Not found", 404)
120 viewModel.deleteAlert("1")
122 val state = viewModel.state.value
123 assertFalse(state.isLoading)
124 assertNotNull(state.error)
125 assertNull(state.alertToDelete)
126 }