Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

Commit 040a6d3

Browse files
authored
Add checkins view model test. (#5715)
1 parent 6fec907 commit 040a6d3

File tree

1 file changed

+281
-0
lines changed

1 file changed

+281
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
package de.rki.coronawarnapp.srs.ui.chekins
2+
3+
import androidx.lifecycle.SavedStateHandle
4+
import de.rki.coronawarnapp.presencetracing.checkins.CheckIn
5+
import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
6+
import de.rki.coronawarnapp.srs.core.model.SrsSubmissionType
7+
import de.rki.coronawarnapp.srs.ui.checkins.SrsCheckinsFragmentViewModel
8+
import de.rki.coronawarnapp.srs.ui.checkins.SrsCheckinsNavigation
9+
import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.consent.HeaderCheckInsVH
10+
import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.consent.SelectableCheckInVH
11+
import io.kotest.matchers.shouldBe
12+
import io.mockk.MockKAnnotations
13+
import io.mockk.Runs
14+
import io.mockk.coEvery
15+
import io.mockk.every
16+
import io.mockk.impl.annotations.MockK
17+
import io.mockk.just
18+
import kotlinx.coroutines.flow.MutableStateFlow
19+
import kotlinx.coroutines.flow.flowOf
20+
import okio.ByteString.Companion.decodeBase64
21+
import okio.ByteString.Companion.encode
22+
import org.junit.jupiter.api.BeforeEach
23+
import org.junit.jupiter.api.Test
24+
import org.junit.jupiter.api.extension.ExtendWith
25+
import testhelpers.TestDispatcherProvider
26+
import testhelpers.extensions.InstantExecutorExtension
27+
import testhelpers.extensions.getOrAwaitValue
28+
import java.time.Instant
29+
30+
@ExtendWith(InstantExecutorExtension::class)
31+
open class SrsCheckinsViewModelTest {
32+
33+
@MockK lateinit var checkInRepository: CheckInRepository
34+
@MockK lateinit var savedState: SavedStateHandle
35+
@MockK lateinit var submissionType: SrsSubmissionType
36+
37+
private val selectedFlow = MutableStateFlow<Set<Long>>(emptySet())
38+
39+
private val checkIn1 = CheckIn(
40+
id = 1L,
41+
traceLocationId = "41da2115-eba2-49bd-bf17-adb3d635ddaf".decodeBase64()!!,
42+
version = 1,
43+
type = 2,
44+
description = "brothers birthday",
45+
address = "Malibu",
46+
traceLocationStart = Instant.EPOCH,
47+
traceLocationEnd = null,
48+
defaultCheckInLengthInMinutes = null,
49+
cryptographicSeed = "cryptographicSeed".encode(),
50+
cnPublicKey = "cnPublicKey",
51+
checkInStart = Instant.EPOCH,
52+
checkInEnd = Instant.EPOCH,
53+
completed = true,
54+
createJournalEntry = false
55+
)
56+
57+
private val checkIn2 = CheckIn(
58+
id = 2L,
59+
traceLocationId = "41da2115-eba2-49bd-bf17-adb3d635ddaf".decodeBase64()!!,
60+
version = 1,
61+
type = 2,
62+
description = "brothers birthday",
63+
address = "Malibu",
64+
traceLocationStart = Instant.EPOCH,
65+
traceLocationEnd = null,
66+
defaultCheckInLengthInMinutes = null,
67+
cryptographicSeed = "cryptographicSeed".encode(),
68+
cnPublicKey = "cnPublicKey",
69+
checkInStart = Instant.EPOCH,
70+
checkInEnd = Instant.EPOCH,
71+
completed = true,
72+
createJournalEntry = false
73+
)
74+
75+
private val checkIn3 = CheckIn(
76+
id = 3L,
77+
traceLocationId = "41da2115-eba2-49bd-bf17-adb3d635ddaf".decodeBase64()!!,
78+
version = 1,
79+
type = 2,
80+
description = "brothers birthday",
81+
address = "Malibu",
82+
traceLocationStart = Instant.EPOCH,
83+
traceLocationEnd = null,
84+
defaultCheckInLengthInMinutes = null,
85+
cryptographicSeed = "cryptographicSeed".encode(),
86+
cnPublicKey = "cnPublicKey",
87+
checkInStart = Instant.EPOCH,
88+
checkInEnd = Instant.EPOCH,
89+
completed = false,
90+
createJournalEntry = false
91+
)
92+
93+
@BeforeEach
94+
fun setUp() {
95+
MockKAnnotations.init(this)
96+
97+
every { checkInRepository.checkInsWithinRetention } returns flowOf(listOf(checkIn1, checkIn2, checkIn3))
98+
coEvery { checkInRepository.updateSubmissionConsents(any(), true) } just Runs
99+
coEvery { checkInRepository.updateSubmissionConsents(any(), false) } just Runs
100+
every { savedState[any()] = any<Set<Long>>() } just Runs
101+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
102+
}
103+
104+
@Test
105+
fun `Nothing is selected initially`() {
106+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
107+
108+
val viewModel = createViewModel()
109+
viewModel.checkIns.getOrAwaitValue().apply {
110+
size shouldBe 3
111+
get(0).apply {
112+
this is HeaderCheckInsVH.Item
113+
}
114+
115+
get(1).apply {
116+
this as SelectableCheckInVH.Item
117+
this.checkIn.hasSubmissionConsent shouldBe false
118+
}
119+
120+
get(2).apply {
121+
this as SelectableCheckInVH.Item
122+
this.checkIn.hasSubmissionConsent shouldBe false
123+
}
124+
}
125+
}
126+
127+
@Test
128+
fun `Saved state is restored`() {
129+
every { savedState.get<Set<Long>>(any()) } returns setOf(1L)
130+
val viewModel = createViewModel()
131+
viewModel.checkIns.getOrAwaitValue().apply {
132+
size shouldBe 3
133+
get(0).apply {
134+
this is HeaderCheckInsVH.Item
135+
}
136+
137+
get(1).apply {
138+
this as SelectableCheckInVH.Item
139+
this.checkIn.hasSubmissionConsent shouldBe true
140+
}
141+
142+
get(2).apply {
143+
this as SelectableCheckInVH.Item
144+
this.checkIn.hasSubmissionConsent shouldBe false
145+
}
146+
}
147+
}
148+
149+
@Test
150+
fun `Select all`() {
151+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
152+
val viewModel = createViewModel()
153+
viewModel.checkIns.getOrAwaitValue().apply {
154+
size shouldBe 3
155+
get(0).apply {
156+
this as HeaderCheckInsVH.Item
157+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe false
158+
(get(2) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe false
159+
160+
this.selectAll()
161+
162+
viewModel.checkIns.getOrAwaitValue().apply {
163+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
164+
(get(2) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
165+
}
166+
}
167+
}
168+
}
169+
170+
@Test
171+
fun `Select all does not un-select all`() {
172+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
173+
val viewModel = createViewModel()
174+
viewModel.checkIns.getOrAwaitValue().apply {
175+
size shouldBe 3
176+
get(0).apply {
177+
this as HeaderCheckInsVH.Item
178+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe false
179+
(get(2) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe false
180+
181+
this.selectAll()
182+
183+
viewModel.checkIns.getOrAwaitValue().apply {
184+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
185+
(get(2) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
186+
}
187+
188+
this.selectAll()
189+
190+
viewModel.checkIns.getOrAwaitValue().apply {
191+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
192+
(get(2) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
193+
}
194+
}
195+
}
196+
}
197+
198+
@Test
199+
fun `Single selection`() {
200+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
201+
val viewModel = createViewModel()
202+
viewModel.checkIns.getOrAwaitValue().apply {
203+
204+
(get(1) as SelectableCheckInVH.Item).apply {
205+
checkIn.hasSubmissionConsent shouldBe false
206+
onItemSelected(checkIn)
207+
}
208+
209+
viewModel.checkIns.getOrAwaitValue().apply {
210+
(get(1) as SelectableCheckInVH.Item).checkIn.hasSubmissionConsent shouldBe true
211+
}
212+
}
213+
}
214+
215+
@Test
216+
fun `Single deselection`() {
217+
every { savedState.get<Set<Long>>(any()) } returns emptySet()
218+
val viewModel = createViewModel()
219+
viewModel.checkIns.getOrAwaitValue().apply {
220+
(get(1) as SelectableCheckInVH.Item).apply {
221+
checkIn.hasSubmissionConsent shouldBe false
222+
onItemSelected(checkIn)
223+
}
224+
225+
viewModel.checkIns.getOrAwaitValue().apply {
226+
(get(1) as SelectableCheckInVH.Item).apply {
227+
checkIn.hasSubmissionConsent shouldBe true
228+
onItemSelected(checkIn)
229+
}
230+
}
231+
232+
viewModel.checkIns.getOrAwaitValue().apply {
233+
(get(1) as SelectableCheckInVH.Item).apply {
234+
checkIn.hasSubmissionConsent shouldBe false
235+
}
236+
}
237+
}
238+
}
239+
240+
@Test
241+
fun `Confirming cancel goes to home screen`() {
242+
createViewModel().apply {
243+
goHome()
244+
events.getOrAwaitValue() shouldBe SrsCheckinsNavigation.GoToHome
245+
}
246+
}
247+
248+
@Test
249+
fun `Skip opens skipDialog`() {
250+
createViewModel().apply {
251+
onSkipClick()
252+
events.getOrAwaitValue() shouldBe SrsCheckinsNavigation.ShowSkipDialog
253+
}
254+
}
255+
256+
@Test
257+
fun `Close opens closeDialog `() {
258+
createViewModel().apply {
259+
onCloseClick()
260+
events.getOrAwaitValue() shouldBe SrsCheckinsNavigation.ShowCloseDialog
261+
}
262+
}
263+
264+
@Test
265+
fun `Pass selected checkins to symptom intro screen when submit button is clicked`() {
266+
createViewModel().apply {
267+
onNextClick()
268+
events.getOrAwaitValue() shouldBe SrsCheckinsNavigation.GoToSymptomSubmission(
269+
submissionType,
270+
selectedFlow.value.toLongArray()
271+
)
272+
}
273+
}
274+
275+
private fun createViewModel() = SrsCheckinsFragmentViewModel(
276+
savedState = savedState,
277+
dispatcherProvider = TestDispatcherProvider(),
278+
checkInRepository = checkInRepository,
279+
submissionType = submissionType
280+
)
281+
}

0 commit comments

Comments
 (0)