summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-11-16 01:04:09 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-11-16 09:34:26 +0100
commit3455fda161edca6f575cc78796ffc87331bcbea7 (patch)
treedf8bd90d2b543dbf84fb204501b38f802e542cd1 /android
parent9fefdc3d5a9b7f6815d67db121d73cea90edbff7 (diff)
downloadmullvadvpn-3455fda161edca6f575cc78796ffc87331bcbea7.tar.xz
mullvadvpn-3455fda161edca6f575cc78796ffc87331bcbea7.zip
Add payment unit tests for welcome view model
Diffstat (limited to 'android')
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt132
1 files changed, 130 insertions, 2 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
index b16eeec2f8..e958df9337 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
@@ -1,19 +1,29 @@
package net.mullvad.mullvadvpn.viewmodel
+import android.app.Activity
import androidx.lifecycle.viewModelScope
import app.cash.turbine.test
import io.mockk.coEvery
+import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlin.test.assertEquals
import kotlin.test.assertIs
+import kotlin.test.assertNull
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.compose.dialog.payment.PaymentDialogData
+import net.mullvad.mullvadvpn.compose.state.PaymentState
import net.mullvad.mullvadvpn.compose.state.WelcomeUiState
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
+import net.mullvad.mullvadvpn.lib.common.test.assertLists
+import net.mullvad.mullvadvpn.lib.payment.model.PaymentAvailability
+import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct
+import net.mullvad.mullvadvpn.lib.payment.model.ProductId
+import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
import net.mullvad.mullvadvpn.model.AccountAndDevice
import net.mullvad.mullvadvpn.model.AccountExpiry
import net.mullvad.mullvadvpn.model.Device
@@ -27,6 +37,8 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache
+import net.mullvad.mullvadvpn.usecase.PaymentUseCase
+import net.mullvad.mullvadvpn.util.toPaymentDialogData
import net.mullvad.talpid.util.EventNotifier
import org.joda.time.DateTime
import org.joda.time.ReadableInstant
@@ -42,6 +54,8 @@ class WelcomeViewModelTest {
MutableStateFlow<ServiceConnectionState>(ServiceConnectionState.Disconnected)
private val deviceState = MutableStateFlow<DeviceState>(DeviceState.Initial)
private val accountExpiryState = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing)
+ private val purchaseResult = MutableStateFlow<PurchaseResult?>(null)
+ private val paymentAvailability = MutableStateFlow<PaymentAvailability?>(null)
// Service connections
private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk()
@@ -50,15 +64,17 @@ class WelcomeViewModelTest {
// Event notifiers
private val eventNotifierTunnelUiState = EventNotifier<TunnelState>(TunnelState.Disconnected)
- private val mockAccountRepository: AccountRepository = mockk()
+ private val mockAccountRepository: AccountRepository = mockk(relaxed = true)
private val mockDeviceRepository: DeviceRepository = mockk()
private val mockServiceConnectionManager: ServiceConnectionManager = mockk()
+ private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true)
private lateinit var viewModel: WelcomeViewModel
@Before
fun setUp() {
mockkStatic(SERVICE_CONNECTION_MANAGER_EXTENSIONS)
+ mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS)
every { mockDeviceRepository.deviceState } returns deviceState
@@ -70,11 +86,16 @@ class WelcomeViewModelTest {
every { mockAccountRepository.accountExpiryState } returns accountExpiryState
+ coEvery { mockPaymentUseCase.purchaseResult } returns purchaseResult
+
+ coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailability
+
viewModel =
WelcomeViewModel(
accountRepository = mockAccountRepository,
deviceRepository = mockDeviceRepository,
serviceConnectionManager = mockServiceConnectionManager,
+ paymentUseCase = mockPaymentUseCase,
pollAccountExpiry = false
)
}
@@ -112,9 +133,9 @@ class WelcomeViewModelTest {
// Act, Assert
viewModel.uiState.test {
assertEquals(WelcomeUiState(), awaitItem())
+ eventNotifierTunnelUiState.notify(tunnelUiStateTestItem)
serviceConnectionState.value =
ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- eventNotifierTunnelUiState.notify(tunnelUiStateTestItem)
val result = awaitItem()
assertEquals(tunnelUiStateTestItem, result.tunnelState)
}
@@ -158,8 +179,115 @@ class WelcomeViewModelTest {
}
}
+ @Test
+ fun testBillingProductsUnavailableState() = runTest {
+ // Arrange
+ val productsUnavailable = PaymentAvailability.ProductsUnavailable
+
+ // Act, Assert
+ viewModel.uiState.test {
+ // Default item
+ awaitItem()
+ paymentAvailability.tryEmit(productsUnavailable)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.NoPayment>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsGenericErrorState() = runTest {
+ // Arrange
+ val paymentOtherError = PaymentAvailability.Error.Other(mockk())
+ paymentAvailability.tryEmit(paymentOtherError)
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Generic>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsBillingErrorState() = runTest {
+ // Arrange
+ val paymentBillingError = PaymentAvailability.Error.BillingUnavailable
+ paymentAvailability.value = paymentBillingError
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Billing>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsPaymentAvailableState() = runTest {
+ // Arrange
+ val mockProduct: PaymentProduct = mockk()
+ val expectedProductList = listOf(mockProduct)
+ val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
+ paymentAvailability.value = productsAvailable
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.PaymentAvailable>(result)
+ assertLists(expectedProductList, result.products)
+ }
+ }
+
+ @Test
+ fun testBillingUserCancelled() = runTest {
+ // Arrange
+ val result = PurchaseResult.Completed.Cancelled
+ purchaseResult.value = result
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ every { result.toPaymentDialogData() } returns null
+
+ // Act, Assert
+ viewModel.uiState.test { assertNull(awaitItem().paymentDialogData) }
+ }
+
+ @Test
+ fun testBillingPurchaseSuccess() = runTest {
+ // Arrange
+ val result = PurchaseResult.Completed.Success
+ val expectedData: PaymentDialogData = mockk()
+ purchaseResult.value = result
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ every { result.toPaymentDialogData() } returns expectedData
+
+ // Act, Assert
+ viewModel.uiState.test { assertEquals(expectedData, awaitItem().paymentDialogData) }
+ }
+
+ @Test
+ fun testStartBillingPayment() {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockActivityProvider = mockk<() -> Activity>()
+
+ // Act
+ viewModel.startBillingPayment(mockProductId, mockActivityProvider)
+
+ // Assert
+ coVerify { mockPaymentUseCase.purchaseProduct(mockProductId, mockActivityProvider) }
+ }
+
companion object {
private const val SERVICE_CONNECTION_MANAGER_EXTENSIONS =
"net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManagerExtensionsKt"
+ private const val PURCHASE_RESULT_EXTENSIONS_CLASS =
+ "net.mullvad.mullvadvpn.util.PurchaseResultExtensionsKt"
}
}