Skip to content

Commit d9e95b7

Browse files
committed
Add unit tests for WooPosScanningSetupViewModel to validate navigation and state management
1 parent 14f3a7f commit d9e95b7

File tree

1 file changed

+332
-0
lines changed

1 file changed

+332
-0
lines changed
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
package com.woocommerce.android.ui.woopos.home.scanningsetup
2+
3+
import app.cash.turbine.test
4+
import com.woocommerce.android.R
5+
import com.woocommerce.android.ui.woopos.home.scanningsetup.WooPosScanningSetupState.BarcodeReaderDevice
6+
import com.woocommerce.android.ui.woopos.home.scanningsetup.WooPosScanningSetupState.ScanningSetupStep
7+
import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule
8+
import com.woocommerce.android.viewmodel.ResourceProvider
9+
import kotlinx.coroutines.ExperimentalCoroutinesApi
10+
import kotlinx.coroutines.test.runTest
11+
import org.assertj.core.api.Assertions.assertThat
12+
import org.junit.Rule
13+
import org.junit.Test
14+
import org.mockito.kotlin.mock
15+
import org.mockito.kotlin.whenever
16+
17+
@ExperimentalCoroutinesApi
18+
class WooPosScanningSetupViewModelTest {
19+
@Rule
20+
@JvmField
21+
val coroutinesTestRule = WooPosCoroutineTestRule()
22+
23+
private val resourceProvider: ResourceProvider = mock()
24+
25+
@Test
26+
fun `given initialized, when no action taken, then should start with DeviceSelection step`() = runTest {
27+
// GIVEN
28+
val viewModel = createViewModel()
29+
30+
// THEN
31+
assertThat(viewModel.state.value.currentStep)
32+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
33+
assertThat(viewModel.state.value.selectedDevice).isNull()
34+
}
35+
36+
@Test
37+
fun `given DeviceSelection step, when OTHER device selected, then should navigate to ScannerSetupInfo`() = runTest {
38+
// GIVEN
39+
val viewModel = createViewModel()
40+
41+
// WHEN
42+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.OTHER))
43+
44+
// THEN
45+
assertThat(viewModel.state.value.currentStep)
46+
.isInstanceOf(ScanningSetupStep.ScannerSetupInfo::class.java)
47+
assertThat(viewModel.state.value.selectedDevice).isEqualTo(BarcodeReaderDevice.OTHER)
48+
}
49+
50+
@Test
51+
fun `given DeviceSelection step, when non-OTHER device selected, then should navigate to ScannerHIDModeSetup`() =
52+
runTest {
53+
// GIVEN
54+
val viewModel = createViewModel()
55+
56+
// WHEN
57+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
58+
59+
// THEN
60+
assertThat(viewModel.state.value.currentStep)
61+
.isInstanceOf(ScanningSetupStep.ScannerHIDModeSetup::class.java)
62+
assertThat(viewModel.state.value.selectedDevice).isEqualTo(BarcodeReaderDevice.TERA_1200)
63+
}
64+
65+
@Test
66+
fun `given ScannerHIDModeSetup step, when primary button clicked, then should navigate to ScannerPairModeSetup`() =
67+
runTest {
68+
// GIVEN
69+
val viewModel = createViewModel()
70+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
71+
72+
// WHEN
73+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
74+
75+
// THEN
76+
assertThat(viewModel.state.value.currentStep)
77+
.isInstanceOf(ScanningSetupStep.ScannerPairModeSetup::class.java)
78+
}
79+
80+
@Test
81+
fun `given ScannerPairModeSetup step, when primary button clicked, then should navigate to PairYourScanner`() =
82+
runTest {
83+
// GIVEN
84+
val viewModel = createViewModel()
85+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
86+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
87+
88+
// WHEN
89+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
90+
91+
// THEN
92+
assertThat(viewModel.state.value.currentStep)
93+
.isInstanceOf(ScanningSetupStep.PairYourScanner::class.java)
94+
}
95+
96+
@Test
97+
fun `given PairYourScanner step, when primary button clicked, then should navigate to TestYourScanner`() = runTest {
98+
// GIVEN
99+
val viewModel = createViewModel()
100+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
101+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
102+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
103+
104+
// WHEN
105+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
106+
107+
// THEN
108+
assertThat(viewModel.state.value.currentStep)
109+
.isInstanceOf(ScanningSetupStep.TestYourScanner::class.java)
110+
}
111+
112+
@Test
113+
fun `given ScannerSetupInfo step from DeviceSelection, when secondary button clicked, then should navigate back to DeviceSelection`() =
114+
runTest {
115+
// GIVEN
116+
val viewModel = createViewModel()
117+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.OTHER))
118+
119+
// WHEN
120+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnSecondaryButtonClicked)
121+
122+
// THEN
123+
assertThat(viewModel.state.value.currentStep)
124+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
125+
}
126+
127+
@Test
128+
fun `given ScannerHIDModeSetup step, when secondary button clicked, then should navigate back to DeviceSelection`() =
129+
runTest {
130+
// GIVEN
131+
val viewModel = createViewModel()
132+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
133+
134+
// WHEN
135+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnSecondaryButtonClicked)
136+
137+
// THEN
138+
assertThat(viewModel.state.value.currentStep)
139+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
140+
}
141+
142+
@Test
143+
fun `given ScannerPairModeSetup step, when secondary button clicked, then should navigate back to ScannerHIDModeSetup`() =
144+
runTest {
145+
// GIVEN
146+
val viewModel = createViewModel()
147+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
148+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
149+
150+
// WHEN
151+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnSecondaryButtonClicked)
152+
153+
// THEN
154+
assertThat(viewModel.state.value.currentStep)
155+
.isInstanceOf(ScanningSetupStep.ScannerHIDModeSetup::class.java)
156+
}
157+
158+
@Test
159+
fun `given PairYourScanner step, when secondary button clicked, then should navigate back to ScannerPairModeSetup`() =
160+
runTest {
161+
// GIVEN
162+
val viewModel = createViewModel()
163+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
164+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
165+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
166+
167+
// WHEN
168+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnSecondaryButtonClicked)
169+
170+
// THEN
171+
assertThat(viewModel.state.value.currentStep)
172+
.isInstanceOf(ScanningSetupStep.ScannerPairModeSetup::class.java)
173+
}
174+
175+
@Test
176+
fun `given TestYourScanner step, when secondary button clicked, then should navigate back to PairYourScanner`() =
177+
runTest {
178+
// GIVEN
179+
val viewModel = createViewModel()
180+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
181+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
182+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
183+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
184+
185+
// WHEN
186+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnSecondaryButtonClicked)
187+
188+
// THEN
189+
assertThat(viewModel.state.value.currentStep)
190+
.isInstanceOf(ScanningSetupStep.PairYourScanner::class.java)
191+
}
192+
193+
@Test
194+
fun `given ScannerSetupInfo step, when primary button clicked, then should emit dismiss dialog event`() = runTest {
195+
// GIVEN
196+
val viewModel = createViewModel()
197+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.OTHER))
198+
199+
viewModel.dismissDialogEvent.test {
200+
// WHEN
201+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
202+
203+
// THEN
204+
awaitItem()
205+
}
206+
}
207+
208+
@Test
209+
fun `given OnOpenBluetoothSettings event, when triggered, then should emit openBluetoothSettingsEvent`() = runTest {
210+
// GIVEN
211+
val viewModel = createViewModel()
212+
213+
viewModel.openBluetoothSettingsEvent.test {
214+
// WHEN
215+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnOpenBluetoothSettings)
216+
217+
// THEN
218+
awaitItem()
219+
}
220+
}
221+
222+
@Test
223+
fun `given resetToInitialState called, when invoked, then should reset to DeviceSelection step`() = runTest {
224+
// GIVEN
225+
val viewModel = createViewModel()
226+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
227+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
228+
229+
// WHEN
230+
viewModel.resetToInitialState()
231+
232+
// THEN
233+
assertThat(viewModel.state.value.currentStep)
234+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
235+
assertThat(viewModel.state.value.selectedDevice).isNull()
236+
}
237+
238+
@Test
239+
fun `given ScannerSetupInfo step, when verifying previousStep is tracked, then should maintain proper navigation history`() =
240+
runTest {
241+
// GIVEN
242+
val viewModel = createViewModel()
243+
244+
// WHEN
245+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.OTHER))
246+
247+
// THEN
248+
val currentStep = viewModel.state.value.currentStep as ScanningSetupStep.ScannerSetupInfo
249+
assertThat(currentStep.previousStep)
250+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
251+
}
252+
253+
@Test
254+
fun `given multi-step navigation, when checking previousStep chain, then should maintain proper navigation stack`() =
255+
runTest {
256+
// GIVEN
257+
val viewModel = createViewModel()
258+
259+
// WHEN
260+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnDeviceSelected(BarcodeReaderDevice.TERA_1200))
261+
viewModel.onUiEvent(WooPosScanningSetupUiEvent.OnPrimaryButtonClicked)
262+
263+
// THEN
264+
val currentStep = viewModel.state.value.currentStep as ScanningSetupStep.ScannerPairModeSetup
265+
assertThat(currentStep.previousStep)
266+
.isInstanceOf(ScanningSetupStep.ScannerHIDModeSetup::class.java)
267+
268+
val previousStep = currentStep.previousStep as ScanningSetupStep.ScannerHIDModeSetup
269+
assertThat(previousStep.previousStep)
270+
.isInstanceOf(ScanningSetupStep.DeviceSelection::class.java)
271+
}
272+
273+
private fun createViewModel(): WooPosScanningSetupViewModel {
274+
setupMockResourceProvider()
275+
return WooPosScanningSetupViewModel(resourceProvider)
276+
}
277+
278+
private fun setupMockResourceProvider() {
279+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_device_selection_title))
280+
.thenReturn("Set up a barcode scanner")
281+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_introduction_title))
282+
.thenReturn("Introduction")
283+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_introduction_message))
284+
.thenReturn("Introduction message")
285+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_scanner_pair_mode_title))
286+
.thenReturn("Pair mode")
287+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_scanner_pair_mode_message))
288+
.thenReturn("Pair mode message")
289+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_pair_your_scanner_title))
290+
.thenReturn("Pair your scanner")
291+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_pair_your_scanner_message, "TERA 1200"))
292+
.thenReturn("Pair your scanner message TERA 1200")
293+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_test_scanner_title))
294+
.thenReturn("Test scanner")
295+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_test_scanner_message))
296+
.thenReturn("Test scanner message")
297+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_success_title))
298+
.thenReturn("Success")
299+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_success_message))
300+
.thenReturn("Success message")
301+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_title))
302+
.thenReturn("Info")
303+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_message))
304+
.thenReturn("Info message")
305+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_bullet_1))
306+
.thenReturn("Bullet 1")
307+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_bullet_2))
308+
.thenReturn("Bullet 2")
309+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_bullet_3))
310+
.thenReturn("Bullet 3")
311+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_info_text))
312+
.thenReturn("Info text")
313+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_button_next))
314+
.thenReturn("Next")
315+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_button_back))
316+
.thenReturn("Back")
317+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_button_done))
318+
.thenReturn("Done")
319+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_go_to_settings))
320+
.thenReturn("Go to settings")
321+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_more_information))
322+
.thenReturn("More information")
323+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_device_tera_1200))
324+
.thenReturn("TERA 1200")
325+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_device_star_bsh_20b))
326+
.thenReturn("STAR BSH 20B")
327+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_device_inateck_bluetooth))
328+
.thenReturn("INATECK Bluetooth")
329+
whenever(resourceProvider.getString(R.string.woopos_scanning_setup_device_other))
330+
.thenReturn("Other")
331+
}
332+
}

0 commit comments

Comments
 (0)