diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 01:04:09 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 09:34:26 +0100 |
| commit | 3455fda161edca6f575cc78796ffc87331bcbea7 (patch) | |
| tree | df8bd90d2b543dbf84fb204501b38f802e542cd1 /android | |
| parent | 9fefdc3d5a9b7f6815d67db121d73cea90edbff7 (diff) | |
| download | mullvadvpn-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.kt | 132 |
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" } } |
