summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorsaber safavi <saber.safavi@codic.se>2023-07-28 15:53:47 +0200
committersaber safavi <saber.safavi@codic.se>2023-07-28 16:54:16 +0200
commitf96271feeac04dcf946bea3adc5ca0e0bd48a3aa (patch)
treeeeefa81c128999cc2baa2edfa61b64b5030df664
parenta202afc1ecd9c07ccda3efb06e044ecd1d4c9a34 (diff)
downloadmullvadvpn-f96271feeac04dcf946bea3adc5ca0e0bd48a3aa.tar.xz
mullvadvpn-f96271feeac04dcf946bea3adc5ca0e0bd48a3aa.zip
Add UI and VM unit tests
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt128
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt97
2 files changed, 225 insertions, 0 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt
new file mode 100644
index 0000000000..e616f67449
--- /dev/null
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt
@@ -0,0 +1,128 @@
+package net.mullvad.mullvadvpn.compose.screen
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import io.mockk.MockKAnnotations
+import io.mockk.mockk
+import io.mockk.verify
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import net.mullvad.mullvadvpn.compose.state.AccountUiState
+import net.mullvad.mullvadvpn.viewmodel.AccountViewModel
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class AccountScreenTest {
+ @get:Rule val composeTestRule = createComposeRule()
+
+ @Before
+ fun setup() {
+ MockKAnnotations.init(this)
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun testDefaultState() {
+ // Arrange
+ composeTestRule.setContent {
+ AccountScreen(
+ uiState =
+ AccountUiState(
+ deviceName = DUMMY_DEVICE_NAME,
+ accountNumber = DUMMY_ACCOUNT_NUMBER,
+ accountExpiry = null
+ ),
+ viewActions = MutableSharedFlow<AccountViewModel.ViewAction>().asSharedFlow()
+ )
+ }
+
+ // Assert
+ composeTestRule.apply {
+ onNodeWithText("Redeem voucher").assertExists()
+ onNodeWithText("Log out").assertExists()
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun testManageAccountClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AccountScreen(
+ uiState =
+ AccountUiState(
+ deviceName = DUMMY_DEVICE_NAME,
+ accountNumber = DUMMY_ACCOUNT_NUMBER,
+ accountExpiry = null
+ ),
+ viewActions = MutableSharedFlow<AccountViewModel.ViewAction>().asSharedFlow(),
+ onManageAccountClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Manage account").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun testRedeemVoucherClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AccountScreen(
+ uiState =
+ AccountUiState(
+ deviceName = DUMMY_DEVICE_NAME,
+ accountNumber = DUMMY_ACCOUNT_NUMBER,
+ accountExpiry = null
+ ),
+ viewActions = MutableSharedFlow<AccountViewModel.ViewAction>().asSharedFlow(),
+ onRedeemVoucherClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Redeem voucher").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun testLogoutClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AccountScreen(
+ uiState =
+ AccountUiState(
+ deviceName = DUMMY_DEVICE_NAME,
+ accountNumber = DUMMY_ACCOUNT_NUMBER,
+ accountExpiry = null
+ ),
+ viewActions = MutableSharedFlow<AccountViewModel.ViewAction>().asSharedFlow(),
+ onLogoutClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Log out").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ companion object {
+ private const val DUMMY_DEVICE_NAME = "fake_name"
+ private const val DUMMY_ACCOUNT_NUMBER = "fake_number"
+ }
+}
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
new file mode 100644
index 0000000000..e5a3f2b397
--- /dev/null
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
@@ -0,0 +1,97 @@
+package net.mullvad.mullvadvpn.viewmodel
+
+import app.cash.turbine.test
+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 kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.TestCoroutineRule
+import net.mullvad.mullvadvpn.model.AccountAndDevice
+import net.mullvad.mullvadvpn.model.AccountExpiry
+import net.mullvad.mullvadvpn.model.Device
+import net.mullvad.mullvadvpn.model.DeviceState
+import net.mullvad.mullvadvpn.repository.AccountRepository
+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 org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class AccountViewModelTest {
+ @get:Rule val testCoroutineRule = TestCoroutineRule()
+
+ private val mockAccountRepository: AccountRepository = mockk(relaxUnitFun = true)
+ private val mockServiceConnectionManager: ServiceConnectionManager = mockk()
+ private val mockDeviceRepository: DeviceRepository = mockk()
+ private val mockAuthTokenCache: AuthTokenCache = mockk()
+
+ private val deviceState: MutableStateFlow<DeviceState> = MutableStateFlow(DeviceState.Initial)
+ private val accountExpiryState = MutableStateFlow(AccountExpiry.Missing)
+
+ private val dummyAccountAndDevice: AccountAndDevice =
+ AccountAndDevice(
+ DUMMY_DEVICE_NAME,
+ Device(
+ id = "fake_id",
+ name = "fake_name",
+ pubkey = byteArrayOf(),
+ ports = ArrayList(),
+ created = "mock_date"
+ )
+ )
+
+ private lateinit var viewModel: AccountViewModel
+
+ @Before
+ fun setUp() {
+ mockkStatic(CACHE_EXTENSION_CLASS)
+ every { mockServiceConnectionManager.authTokenCache() } returns mockAuthTokenCache
+ every { mockDeviceRepository.deviceState } returns deviceState
+ every { mockAccountRepository.accountExpiryState } returns accountExpiryState
+
+ viewModel =
+ AccountViewModel(
+ accountRepository = mockAccountRepository,
+ serviceConnectionManager = mockServiceConnectionManager,
+ deviceRepository = mockDeviceRepository
+ )
+ }
+
+ @After
+ fun tearDown() {
+ unmockkAll()
+ }
+
+ @Test
+ fun testAccountLoggedInState() = runTest {
+ // Act, Assert
+ viewModel.uiState.test {
+ var result = awaitItem()
+ assertEquals("", result.deviceName)
+ deviceState.value = DeviceState.LoggedIn(accountAndDevice = dummyAccountAndDevice)
+ result = awaitItem()
+ assertEquals(DUMMY_DEVICE_NAME, result.accountNumber)
+ }
+ }
+
+ @Test
+ fun testOnLogoutClick() {
+ // Act
+ viewModel.onLogoutClick()
+
+ // Assert
+ verify { mockAccountRepository.logout() }
+ }
+
+ companion object {
+ private const val CACHE_EXTENSION_CLASS = "net.mullvad.mullvadvpn.util.CacheExtensionsKt"
+ private const val DUMMY_DEVICE_NAME = "fake_name"
+ }
+}