summaryrefslogtreecommitdiffhomepage
path: root/android/app/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src/test')
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt154
1 files changed, 88 insertions, 66 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
index 4ba80511c6..73bfd1ef38 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
@@ -2,58 +2,48 @@ package net.mullvad.mullvadvpn.viewmodel
import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
+import app.cash.turbine.turbineScope
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.verify
-import junit.framework.Assert.assertEquals
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
-import net.mullvad.mullvadvpn.lib.ipc.Event
+import net.mullvad.mullvadvpn.compose.state.LoginError
+import net.mullvad.mullvadvpn.compose.state.LoginState.*
+import net.mullvad.mullvadvpn.compose.state.LoginUiState
+import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
import net.mullvad.mullvadvpn.model.AccountCreationResult
import net.mullvad.mullvadvpn.model.AccountHistory
+import net.mullvad.mullvadvpn.model.AccountToken
import net.mullvad.mullvadvpn.model.DeviceListEvent
import net.mullvad.mullvadvpn.model.LoginResult
import net.mullvad.mullvadvpn.repository.AccountRepository
import net.mullvad.mullvadvpn.repository.DeviceRepository
-import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer
-import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
+import org.junit.Assert.assertEquals
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
class LoginViewModelTest {
+ @get:Rule val testCoroutineRule = TestCoroutineRule()
@MockK private lateinit var mockedAccountRepository: AccountRepository
-
@MockK private lateinit var mockedDeviceRepository: DeviceRepository
- @MockK private lateinit var mockedServiceConnectionContainer: ServiceConnectionContainer
-
private lateinit var loginViewModel: LoginViewModel
-
- private val accountCreationTestEvents = MutableSharedFlow<AccountCreationResult>()
private val accountHistoryTestEvents = MutableStateFlow<AccountHistory>(AccountHistory.Missing)
- private val loginTestEvents = MutableSharedFlow<Event.LoginEvent>()
-
- private val serviceConnectionState =
- MutableStateFlow<ServiceConnectionState>(ServiceConnectionState.Disconnected)
@Before
fun setup() {
Dispatchers.setMain(UnconfinedTestDispatcher())
MockKAnnotations.init(this, relaxUnitFun = true)
- every { mockedAccountRepository.accountCreationEvents } returns accountCreationTestEvents
- every { mockedAccountRepository.accountHistoryEvents } returns accountHistoryTestEvents
- every { mockedAccountRepository.loginEvents } returns loginTestEvents
-
- serviceConnectionState.value =
- ServiceConnectionState.ConnectedReady(mockedServiceConnectionContainer)
+ every { mockedAccountRepository.accountHistory } returns accountHistoryTestEvents
loginViewModel =
LoginViewModel(
@@ -64,103 +54,135 @@ class LoginViewModelTest {
}
@Test
- fun testDefaultState() = runBlockingTest {
- loginViewModel.uiState.test {
- assertEquals(LoginViewModel.LoginUiState.Default, awaitItem())
- }
+ fun testDefaultState() = runTest {
+ loginViewModel.uiState.test { assertEquals(LoginUiState.INITIAL, awaitItem()) }
}
@Test
- fun testCreateAccount() = runBlockingTest {
- loginViewModel.uiState.test {
- skipDefaultItem()
- loginViewModel.createAccount()
- assertEquals(LoginViewModel.LoginUiState.CreatingAccount, awaitItem())
- accountCreationTestEvents.emit(AccountCreationResult.Success(DUMMY_ACCOUNT_TOKEN))
+ fun testCreateAccount() = runTest {
+ turbineScope {
+ // Arrange
+ val uiStates = loginViewModel.uiState.testIn(backgroundScope)
+ val sideEffects = loginViewModel.viewActions.testIn(backgroundScope)
+ coEvery { mockedAccountRepository.createAccount() } returns
+ AccountCreationResult.Success(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.AccountCreated, awaitItem())
+ // Act, Assert
+ uiStates.skipDefaultItem()
+ loginViewModel.createAccount()
+ assertEquals(Loading.CreatingAccount, uiStates.awaitItem().loginState)
+ assertEquals(LoginViewAction.NavigateToWelcome, sideEffects.awaitItem())
}
}
@Test
- fun testLoginWithValidAccount() = runBlockingTest {
- loginViewModel.uiState.test {
- skipDefaultItem()
+ fun testLoginWithValidAccount() = runTest {
+ turbineScope {
+ // Arrange
+ val uiStates = loginViewModel.uiState.testIn(backgroundScope)
+ val sideEffects = loginViewModel.viewActions.testIn(backgroundScope)
+ coEvery { mockedAccountRepository.login(any()) } returns LoginResult.Ok
+
+ // Act, Assert
+ uiStates.skipDefaultItem()
loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.Loading, awaitItem())
- loginTestEvents.emit(Event.LoginEvent(LoginResult.Ok))
- assertEquals(LoginViewModel.LoginUiState.Success(isOutOfTime = false), awaitItem())
+ assertEquals(Loading.LoggingIn, uiStates.awaitItem().loginState)
+ assertEquals(Success, uiStates.awaitItem().loginState)
+ assertEquals(LoginViewAction.NavigateToConnect, sideEffects.awaitItem())
}
}
@Test
- fun testLoginWithInvalidAccount() = runBlockingTest {
+ fun testLoginWithInvalidAccount() = runTest {
loginViewModel.uiState.test {
+ // Arrange
+ coEvery { mockedAccountRepository.login(any()) } returns LoginResult.InvalidAccount
+
+ // Act, Assert
skipDefaultItem()
loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.Loading, awaitItem())
- loginTestEvents.emit(Event.LoginEvent(LoginResult.InvalidAccount))
- assertEquals(LoginViewModel.LoginUiState.InvalidAccountError, awaitItem())
+ assertEquals(Loading.LoggingIn, awaitItem().loginState)
+ assertEquals(Idle(loginError = LoginError.InvalidCredentials), awaitItem().loginState)
}
}
@Test
- fun testLoginWithTooManyDevicesError() = runBlockingTest {
- coEvery {
- mockedDeviceRepository.refreshAndAwaitDeviceListWithTimeout(any(), any(), any(), any())
- } returns DeviceListEvent.Available(DUMMY_ACCOUNT_TOKEN, listOf())
+ fun testLoginWithTooManyDevicesError() = runTest {
+ turbineScope {
+ // Arrange
+ val uiStates = loginViewModel.uiState.testIn(backgroundScope)
+ val sideEffects = loginViewModel.viewActions.testIn(backgroundScope)
+ coEvery {
+ mockedDeviceRepository.refreshAndAwaitDeviceListWithTimeout(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ } returns DeviceListEvent.Available(DUMMY_ACCOUNT_TOKEN, listOf())
+ coEvery { mockedAccountRepository.login(any()) } returns LoginResult.MaxDevicesReached
- loginViewModel.uiState.test {
- skipDefaultItem()
+ // Act, Assert
+ uiStates.skipDefaultItem()
loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.Loading, awaitItem())
- loginTestEvents.emit(Event.LoginEvent(LoginResult.MaxDevicesReached))
+ assertEquals(Loading.LoggingIn, uiStates.awaitItem().loginState)
assertEquals(
- LoginViewModel.LoginUiState.TooManyDevicesError(DUMMY_ACCOUNT_TOKEN),
- awaitItem()
+ LoginViewAction.TooManyDevices(AccountToken(DUMMY_ACCOUNT_TOKEN)),
+ sideEffects.awaitItem()
)
}
}
@Test
- fun testLoginWithRpcError() = runBlockingTest {
+ fun testLoginWithRpcError() = runTest {
loginViewModel.uiState.test {
+ // Arrange
+ coEvery { mockedAccountRepository.login(any()) } returns LoginResult.RpcError
+
+ // Act, Assert
skipDefaultItem()
loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.Loading, awaitItem())
- loginTestEvents.emit(Event.LoginEvent(LoginResult.RpcError))
+ assertEquals(Loading.LoggingIn, awaitItem().loginState)
assertEquals(
- LoginViewModel.LoginUiState.OtherError(EXPECTED_RPC_ERROR_MESSAGE),
- awaitItem()
+ Idle(LoginError.Unknown(EXPECTED_RPC_ERROR_MESSAGE)),
+ awaitItem().loginState
)
}
}
@Test
- fun testLoginWithUnknownError() = runBlockingTest {
+ fun testLoginWithUnknownError() = runTest {
loginViewModel.uiState.test {
+ // Arrange
+ coEvery { mockedAccountRepository.login(any()) } returns LoginResult.OtherError
+
+ // Act, Assert
skipDefaultItem()
loginViewModel.login(DUMMY_ACCOUNT_TOKEN)
- assertEquals(LoginViewModel.LoginUiState.Loading, awaitItem())
- loginTestEvents.emit(Event.LoginEvent(LoginResult.OtherError))
+ assertEquals(Loading.LoggingIn, awaitItem().loginState)
assertEquals(
- LoginViewModel.LoginUiState.OtherError(EXPECTED_OTHER_ERROR_MESSAGE),
- awaitItem()
+ Idle(LoginError.Unknown(EXPECTED_OTHER_ERROR_MESSAGE)),
+ awaitItem().loginState
)
}
}
@Test
- fun testAccountHistory() = runBlockingTest {
- loginViewModel.accountHistory.test {
+ fun testAccountHistory() = runTest {
+ loginViewModel.uiState.test {
+ // Act, Assert
skipDefaultItem()
accountHistoryTestEvents.emit(AccountHistory.Available(DUMMY_ACCOUNT_TOKEN))
- assertEquals(AccountHistory.Available(DUMMY_ACCOUNT_TOKEN), awaitItem())
+ assertEquals(
+ LoginUiState.INITIAL.copy(lastUsedAccount = AccountToken(DUMMY_ACCOUNT_TOKEN)),
+ awaitItem()
+ )
}
}
@Test
- fun testClearingAccountHistory() = runBlockingTest {
+ fun testClearingAccountHistory() = runTest {
+ // Act, Assert
loginViewModel.clearAccountHistory()
verify { mockedAccountRepository.clearAccountHistory() }
}