diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 01:06:15 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 09:34:26 +0100 |
| commit | 5aac2637cbb9c3acf5504570d8a0014d609ca33b (patch) | |
| tree | e0e4404d53b5939ba650e2f1b6123d67ffa2705c /android/app | |
| parent | 8afe089bb7990328e7d38b8c3133289e36f83203 (diff) | |
| download | mullvadvpn-5aac2637cbb9c3acf5504570d8a0014d609ca33b.tar.xz mullvadvpn-5aac2637cbb9c3acf5504570d8a0014d609ca33b.zip | |
Add payment unit tests for OutOfTimeViewModel
Diffstat (limited to 'android/app')
| -rw-r--r-- | android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt | 152 |
1 files changed, 150 insertions, 2 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt index 8c1ec10f5a..dad51eab59 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt @@ -1,8 +1,10 @@ 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 @@ -10,11 +12,19 @@ import io.mockk.unmockkAll import io.mockk.verify 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.OutOfTimeUiState +import net.mullvad.mullvadvpn.compose.state.PaymentState 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.AccountExpiry import net.mullvad.mullvadvpn.model.DeviceState import net.mullvad.mullvadvpn.model.TunnelState @@ -27,6 +37,8 @@ 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.ui.serviceconnection.connectionProxy +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 OutOfTimeViewModelTest { MutableStateFlow<ServiceConnectionState>(ServiceConnectionState.Disconnected) private val accountExpiryState = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing) private val deviceState = MutableStateFlow<DeviceState>(DeviceState.Initial) + private val paymentAvailability = MutableStateFlow<PaymentAvailability?>(null) + private val purchaseResult = MutableStateFlow<PurchaseResult?>(null) // Service connections private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk() @@ -50,15 +64,17 @@ class OutOfTimeViewModelTest { // Event notifiers private val eventNotifierTunnelRealState = 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: OutOfTimeViewModel @Before fun setUp() { mockkStatic(SERVICE_CONNECTION_MANAGER_EXTENSIONS) + mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS) every { mockServiceConnectionManager.connectionState } returns serviceConnectionState @@ -70,11 +86,16 @@ class OutOfTimeViewModelTest { every { mockDeviceRepository.deviceState } returns deviceState + coEvery { mockPaymentUseCase.purchaseResult } returns purchaseResult + + coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailability + viewModel = OutOfTimeViewModel( accountRepository = mockAccountRepository, serviceConnectionManager = mockServiceConnectionManager, deviceRepository = mockDeviceRepository, + paymentUseCase = mockPaymentUseCase, pollAccountExpiry = false ) } @@ -112,9 +133,9 @@ class OutOfTimeViewModelTest { // Act, Assert viewModel.uiState.test { assertEquals(OutOfTimeUiState(deviceName = ""), awaitItem()) + eventNotifierTunnelRealState.notify(tunnelRealStateTestItem) serviceConnectionState.value = ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) - eventNotifierTunnelRealState.notify(tunnelRealStateTestItem) val result = awaitItem() assertEquals(tunnelRealStateTestItem, result.tunnelState) } @@ -149,8 +170,135 @@ class OutOfTimeViewModelTest { verify { mockProxy.disconnect() } } + @Test + fun testBillingProductsUnavailableState() = runTest { + // Arrange + val productsUnavailable = PaymentAvailability.ProductsUnavailable + paymentAvailability.value = productsUnavailable + serviceConnectionState.value = + ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer) + + // Act, Assert + viewModel.uiState.test { + val result = awaitItem().billingPaymentState + assertIs<PaymentState.NoPayment>(result) + } + } + + @Test + fun testBillingProductsGenericErrorState() = runTest { + // Arrange + val paymentAvailabilityError = PaymentAvailability.Error.Other(mockk()) + paymentAvailability.value = paymentAvailabilityError + 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 paymentAvailabilityError = PaymentAvailability.Error.BillingUnavailable + paymentAvailability.value = paymentAvailabilityError + 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 + 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) } + } + + @Test + fun testOnClosePurchaseResultDialogSuccessful() { + // Arrange + + // Act + viewModel.onClosePurchaseResultDialog(success = true) + + // Assert + verify { mockAccountRepository.fetchAccountExpiry() } + coVerify { mockPaymentUseCase.resetPurchaseResult() } + } + + @Test + fun testOnClosePurchaseResultDialogNotSuccessful() { + // Arrange + + // Act + viewModel.onClosePurchaseResultDialog(success = false) + + // Assert + coVerify { mockPaymentUseCase.queryPaymentAvailability() } + coVerify { mockPaymentUseCase.resetPurchaseResult() } + } + 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" } } |
