test(auth): ForgotPasswordViewModelTest — typed exception + blank-email coverage
This commit is contained in:
parent
1a6cdaa078
commit
f47fa3cdbd
|
|
@ -0,0 +1,89 @@
|
||||||
|
package app.closer.ui.auth
|
||||||
|
|
||||||
|
import app.closer.domain.repository.AuthRepository
|
||||||
|
import app.closer.domain.repository.PasswordResetException
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
|
import kotlinx.coroutines.test.resetMain
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.test.setMain
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the "forgot password" outcomes are mapped from typed [PasswordResetException]s (not fragile
|
||||||
|
* message-string matching) to the right user-facing copy — including the Google-only case.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class ForgotPasswordViewModelTest {
|
||||||
|
|
||||||
|
private val dispatcher = StandardTestDispatcher()
|
||||||
|
private val authRepository: AuthRepository = mockk()
|
||||||
|
|
||||||
|
@Before fun setUp() = Dispatchers.setMain(dispatcher)
|
||||||
|
@After fun tearDown() = Dispatchers.resetMain()
|
||||||
|
|
||||||
|
private fun errorFor(result: Result<Unit>, email: String = "sam@example.com"): String? {
|
||||||
|
coEvery { authRepository.sendPasswordResetEmail(email) } returns result
|
||||||
|
val vm = ForgotPasswordViewModel(authRepository)
|
||||||
|
vm.updateEmail(email)
|
||||||
|
vm.sendReset()
|
||||||
|
dispatcher.scheduler.advanceUntilIdle()
|
||||||
|
return vm.uiState.value.error
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `success flips to sent with no error`() = runTest(dispatcher) {
|
||||||
|
coEvery { authRepository.sendPasswordResetEmail("sam@example.com") } returns Result.success(Unit)
|
||||||
|
val vm = ForgotPasswordViewModel(authRepository)
|
||||||
|
vm.updateEmail("sam@example.com")
|
||||||
|
vm.sendReset()
|
||||||
|
advanceUntilIdle()
|
||||||
|
assertTrue(vm.uiState.value.sent)
|
||||||
|
assertNull(vm.uiState.value.error)
|
||||||
|
assertFalse(vm.uiState.value.isLoading)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `no account maps to a friendly message`() = runTest(dispatcher) {
|
||||||
|
assertEquals(
|
||||||
|
"No account found with that email.",
|
||||||
|
errorFor(Result.failure(PasswordResetException.NoAccount()))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `invalid email maps to a friendly message`() = runTest(dispatcher) {
|
||||||
|
assertEquals(
|
||||||
|
"Please enter a valid email address.",
|
||||||
|
errorFor(Result.failure(PasswordResetException.InvalidEmail()))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `unknown failure falls back to its own message`() = runTest(dispatcher) {
|
||||||
|
assertEquals(
|
||||||
|
"Network down",
|
||||||
|
errorFor(Result.failure(RuntimeException("Network down")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `blank email is rejected without calling the repository`() = runTest(dispatcher) {
|
||||||
|
val vm = ForgotPasswordViewModel(authRepository)
|
||||||
|
vm.updateEmail(" ")
|
||||||
|
vm.sendReset()
|
||||||
|
advanceUntilIdle()
|
||||||
|
assertEquals("Please enter your email address.", vm.uiState.value.error)
|
||||||
|
assertFalse(vm.uiState.value.sent)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue