diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 01:00:20 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 09:34:26 +0100 |
| commit | 06a950f5982d0d56031803a6d96a7bce6701bc08 (patch) | |
| tree | b61f1c95d2d1377629f67233d3a0a24471f06a98 /android | |
| parent | 91a030a18450c5b7bc531544c54df0445746f1fa (diff) | |
| download | mullvadvpn-06a950f5982d0d56031803a6d96a7bce6701bc08.tar.xz mullvadvpn-06a950f5982d0d56031803a6d96a7bce6701bc08.zip | |
Add payment unit tests for AccountViewModel
Diffstat (limited to 'android')
| -rw-r--r-- | android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt | 141 |
1 files changed, 137 insertions, 4 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt index fc1fd5e99b..c02e755951 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt @@ -1,15 +1,27 @@ package net.mullvad.mullvadvpn.viewmodel +import android.app.Activity 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 io.mockk.verify import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNull 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.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 @@ -19,6 +31,8 @@ import net.mullvad.mullvadvpn.repository.DeviceRepository import net.mullvad.mullvadvpn.ui.serviceconnection.AuthTokenCache import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache +import net.mullvad.mullvadvpn.usecase.PaymentUseCase +import net.mullvad.mullvadvpn.util.toPaymentDialogData import org.junit.After import org.junit.Before import org.junit.Rule @@ -31,8 +45,11 @@ class AccountViewModelTest { private val mockServiceConnectionManager: ServiceConnectionManager = mockk() private val mockDeviceRepository: DeviceRepository = mockk() private val mockAuthTokenCache: AuthTokenCache = mockk() + private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true) private val deviceState: MutableStateFlow<DeviceState> = MutableStateFlow(DeviceState.Initial) + private val paymentAvailability = MutableStateFlow<PaymentAvailability?>(null) + private val purchaseResult = MutableStateFlow<PurchaseResult?>(null) private val accountExpiryState = MutableStateFlow(AccountExpiry.Missing) private val dummyAccountAndDevice: AccountAndDevice = @@ -51,15 +68,19 @@ class AccountViewModelTest { @Before fun setUp() { mockkStatic(CACHE_EXTENSION_CLASS) + mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS) every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache every { mockDeviceRepository.deviceState } returns deviceState every { mockAccountRepository.accountExpiryState } returns accountExpiryState + coEvery { mockPaymentUseCase.purchaseResult } returns purchaseResult + coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailability viewModel = AccountViewModel( accountRepository = mockAccountRepository, serviceConnectionManager = mockServiceConnectionManager, - deviceRepository = mockDeviceRepository + deviceRepository = mockDeviceRepository, + paymentUseCase = mockPaymentUseCase ) } @@ -72,10 +93,9 @@ class AccountViewModelTest { fun testAccountLoggedInState() = runTest { // Act, Assert viewModel.uiState.test { - var result = awaitItem() - assertEquals(null, result.deviceName) + awaitItem() // Default state deviceState.value = DeviceState.LoggedIn(accountAndDevice = dummyAccountAndDevice) - result = awaitItem() + val result = awaitItem() assertEquals(DUMMY_DEVICE_NAME, result.accountNumber) } } @@ -89,8 +109,121 @@ class AccountViewModelTest { verify { mockAccountRepository.logout() } } + @Test + fun testBillingProductsUnavailableState() = runTest { + // Arrange in setup + + // Act, Assert + viewModel.uiState.test { + awaitItem() // Default state + paymentAvailability.tryEmit(PaymentAvailability.ProductsUnavailable) + val result = awaitItem().billingPaymentState + assertIs<PaymentState.NoPayment>(result) + } + } + + @Test + fun testBillingProductsGenericErrorState() = runTest { + // Act, Assert + viewModel.uiState.test { + awaitItem() // Default state + paymentAvailability.tryEmit(PaymentAvailability.Error.Other(mockk())) + val result = awaitItem().billingPaymentState + assertIs<PaymentState.Error.Generic>(result) + } + } + + @Test + fun testBillingProductsBillingErrorState() = runTest { + // Act, Assert + viewModel.uiState.test { + awaitItem() // Default state + paymentAvailability.tryEmit(PaymentAvailability.Error.BillingUnavailable) + val result = awaitItem().billingPaymentState + assertIs<PaymentState.Error.Billing>(result) + } + } + + @Test + fun testBillingProductsPaymentAvailableState() = runTest { + // Arrange + val mockProduct: PaymentProduct = mockk() + val expectedProductList = listOf(mockProduct) + + // Act, Assert + viewModel.uiState.test { + awaitItem() // Default state + paymentAvailability.tryEmit(PaymentAvailability.ProductsAvailable(listOf(mockProduct))) + 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 + 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 CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt" + private const val PURCHASE_RESULT_EXTENSIONS_CLASS = + "net.mullvad.mullvadvpn.util.PurchaseResultExtensionsKt" private const val DUMMY_DEVICE_NAME = "fake_name" } } |
